initial 5640 support
This commit is contained in:
@@ -45,6 +45,9 @@
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
#include "ov3660.h"
|
||||
#endif
|
||||
#if CONFIG_OV5640_SUPPORT
|
||||
#include "ov5640.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CAMERA_NONE = 0,
|
||||
@@ -52,6 +55,7 @@ typedef enum {
|
||||
CAMERA_OV7725 = 7725,
|
||||
CAMERA_OV2640 = 2640,
|
||||
CAMERA_OV3660 = 3660,
|
||||
CAMERA_OV5640 = 5640,
|
||||
} camera_model_t;
|
||||
|
||||
#define REG_PID 0x0A
|
||||
@@ -80,6 +84,7 @@ typedef struct camera_fb_s {
|
||||
size_t width;
|
||||
size_t height;
|
||||
pixformat_t format;
|
||||
struct timeval timestamp;
|
||||
size_t size;
|
||||
uint8_t ref;
|
||||
uint8_t bad;
|
||||
@@ -546,6 +551,7 @@ static void IRAM_ATTR signal_dma_buf_received(bool* need_yield)
|
||||
}
|
||||
//ESP_EARLY_LOGW(TAG, "qsf:%d", s_state->dma_received_count);
|
||||
//ets_printf("qsf:%d\n", s_state->dma_received_count);
|
||||
//ets_printf("qovf\n");
|
||||
}
|
||||
*need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE);
|
||||
}
|
||||
@@ -577,6 +583,7 @@ static void IRAM_ATTR vsync_isr(void* arg)
|
||||
if(s_state->dma_filtered_count > 1 || s_state->fb->bad || s_state->config.fb_count > 1) {
|
||||
i2s_stop(&need_yield);
|
||||
}
|
||||
//ets_printf("vs\n");
|
||||
}
|
||||
if(s_state->config.fb_count > 1 || s_state->dma_filtered_count < 2) {
|
||||
I2S0.conf.rx_start = 0;
|
||||
@@ -669,6 +676,7 @@ static void IRAM_ATTR dma_finish_frame()
|
||||
if(s_state->config.fb_count == 1) {
|
||||
i2s_start_bus();
|
||||
}
|
||||
//ets_printf("bad\n");
|
||||
} else {
|
||||
s_state->fb->len = s_state->dma_filtered_count * buf_len;
|
||||
if(s_state->fb->len) {
|
||||
@@ -695,6 +703,8 @@ static void IRAM_ATTR dma_finish_frame()
|
||||
} else if(s_state->config.fb_count == 1){
|
||||
//frame was empty?
|
||||
i2s_start_bus();
|
||||
} else {
|
||||
//ets_printf("empty\n");
|
||||
}
|
||||
}
|
||||
} else if(s_state->fb->len) {
|
||||
@@ -728,15 +738,19 @@ static void IRAM_ATTR dma_filter_buffer(size_t buf_idx)
|
||||
if(s_state->sensor.pixformat == PIXFORMAT_JPEG) {
|
||||
uint32_t sig = *((uint32_t *)s_state->fb->buf) & 0xFFFFFF;
|
||||
if(sig != 0xffd8ff) {
|
||||
//ets_printf("bad header\n");
|
||||
ets_printf("bh 0x%08x\n", sig);
|
||||
s_state->fb->bad = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
//set the frame properties
|
||||
s_state->fb->width = resolution[s_state->sensor.status.framesize][0];
|
||||
s_state->fb->height = resolution[s_state->sensor.status.framesize][1];
|
||||
s_state->fb->width = resolution[s_state->sensor.status.framesize].width;
|
||||
s_state->fb->height = resolution[s_state->sensor.status.framesize].height;
|
||||
s_state->fb->format = s_state->sensor.pixformat;
|
||||
|
||||
uint64_t us = (uint64_t)esp_timer_get_time();
|
||||
s_state->fb->timestamp.tv_sec = us / 1000000UL;
|
||||
s_state->fb->timestamp.tv_usec = us % 1000000UL;
|
||||
}
|
||||
s_state->dma_filtered_count++;
|
||||
}
|
||||
@@ -972,13 +986,6 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
gpio_set_level(config->pin_reset, 1);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
#if (CONFIG_OV2640_SUPPORT && !CONFIG_OV3660_SUPPORT)
|
||||
} else {
|
||||
//reset OV2640
|
||||
SCCB_Write(0x30, 0xFF, 0x01);//bank sensor
|
||||
SCCB_Write(0x30, 0x12, 0x80);//reset
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
#endif
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Searching for camera address");
|
||||
@@ -989,15 +996,13 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
camera_disable_out_clock();
|
||||
return ESP_ERR_CAMERA_NOT_DETECTED;
|
||||
}
|
||||
s_state->sensor.slv_addr = slv_addr;
|
||||
s_state->sensor.xclk_freq_hz = config->xclk_freq_hz;
|
||||
|
||||
//s_state->sensor.slv_addr = 0x30;
|
||||
ESP_LOGD(TAG, "Detected camera at address=0x%02x", s_state->sensor.slv_addr);
|
||||
|
||||
//slv_addr = 0x30;
|
||||
ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr);
|
||||
sensor_id_t* id = &s_state->sensor.id;
|
||||
|
||||
#if (CONFIG_OV2640_SUPPORT)
|
||||
if (s_state->sensor.slv_addr == 0x30) {
|
||||
#if CONFIG_OV2640_SUPPORT
|
||||
if (slv_addr == 0x30) {
|
||||
ESP_LOGD(TAG, "Resetting OV2640");
|
||||
//camera might be OV2640. try to reset it
|
||||
SCCB_Write(0x30, 0xFF, 0x01);//bank sensor
|
||||
@@ -1007,7 +1012,10 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
s_state->sensor.slv_addr = slv_addr;
|
||||
s_state->sensor.xclk_freq_hz = config->xclk_freq_hz;
|
||||
|
||||
#if (CONFIG_OV3660_SUPPORT || CONFIG_OV5640_SUPPORT)
|
||||
if(s_state->sensor.slv_addr == 0x3c){
|
||||
id->PID = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDH);
|
||||
id->VER = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDL);
|
||||
@@ -1022,7 +1030,8 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
|
||||
id->PID, id->VER, id->MIDH, id->MIDL);
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
|
||||
#if (CONFIG_OV3660_SUPPORT || CONFIG_OV5640_SUPPORT)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1045,6 +1054,12 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
*out_camera_model = CAMERA_OV3660;
|
||||
ov3660_init(&s_state->sensor);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_OV5640_SUPPORT
|
||||
case OV5640_PID:
|
||||
*out_camera_model = CAMERA_OV5640;
|
||||
ov5640_init(&s_state->sensor);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
id->PID = 0;
|
||||
@@ -1072,12 +1087,46 @@ esp_err_t camera_init(const camera_config_t* config)
|
||||
esp_err_t err = ESP_OK;
|
||||
framesize_t frame_size = (framesize_t) config->frame_size;
|
||||
pixformat_t pix_format = (pixformat_t) config->pixel_format;
|
||||
s_state->width = resolution[frame_size][0];
|
||||
s_state->height = resolution[frame_size][1];
|
||||
|
||||
switch (s_state->sensor.id.PID) {
|
||||
#if CONFIG_OV2640_SUPPORT
|
||||
case OV2640_PID:
|
||||
if (frame_size > FRAMESIZE_UXGA) {
|
||||
frame_size = FRAMESIZE_UXGA;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_OV7725_SUPPORT
|
||||
case OV7725_PID:
|
||||
if (frame_size > FRAMESIZE_VGA) {
|
||||
frame_size = FRAMESIZE_VGA;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
case OV3660_PID:
|
||||
if (frame_size > FRAMESIZE_QXGA) {
|
||||
frame_size = FRAMESIZE_QXGA;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_OV5640_SUPPORT
|
||||
case OV5640_PID:
|
||||
if (frame_size > FRAMESIZE_QSXGA) {
|
||||
frame_size = FRAMESIZE_QSXGA;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return ESP_ERR_CAMERA_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
s_state->width = resolution[frame_size].width;
|
||||
s_state->height = resolution[frame_size].height;
|
||||
|
||||
if (pix_format == PIXFORMAT_GRAYSCALE) {
|
||||
s_state->fb_size = s_state->width * s_state->height;
|
||||
if (s_state->sensor.id.PID == OV3660_PID) {
|
||||
if (s_state->sensor.id.PID == OV3660_PID || s_state->sensor.id.PID == OV5640_PID) {
|
||||
if (is_hs_mode()) {
|
||||
s_state->sampling_mode = SM_0A00_0B00;
|
||||
s_state->dma_filter = &dma_filter_yuyv_highspeed;
|
||||
@@ -1120,8 +1169,8 @@ esp_err_t camera_init(const camera_config_t* config)
|
||||
s_state->in_bytes_per_pixel = 2; // camera sends RGB565
|
||||
s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888
|
||||
} else if (pix_format == PIXFORMAT_JPEG) {
|
||||
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID) {
|
||||
ESP_LOGE(TAG, "JPEG format is only supported for ov2640 and ov3660");
|
||||
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID && s_state->sensor.id.PID != OV5640_PID) {
|
||||
ESP_LOGE(TAG, "JPEG format is only supported for ov2640, ov3660 and ov5640");
|
||||
err = ESP_ERR_NOT_SUPPORTED;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1268,6 +1317,8 @@ esp_err_t esp_camera_init(const camera_config_t* config)
|
||||
ESP_LOGD(TAG, "Detected OV2640 camera");
|
||||
} else if (camera_model == CAMERA_OV3660) {
|
||||
ESP_LOGD(TAG, "Detected OV3660 camera");
|
||||
} else if (camera_model == CAMERA_OV5640) {
|
||||
ESP_LOGD(TAG, "Detected OV5640 camera");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Camera not supported");
|
||||
err = ESP_ERR_CAMERA_NOT_SUPPORTED;
|
||||
|
||||
@@ -115,6 +115,7 @@ typedef struct {
|
||||
size_t width; /*!< Width of the buffer in pixels */
|
||||
size_t height; /*!< Height of the buffer in pixels */
|
||||
pixformat_t format; /*!< Format of the pixel data */
|
||||
struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
|
||||
} camera_fb_t;
|
||||
|
||||
#define ESP_ERR_CAMERA_BASE 0x20000
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#ifndef __SENSOR_H__
|
||||
#define __SENSOR_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define OV9650_PID (0x96)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV7725_PID (0x77)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV3660_PID (0x36)
|
||||
#define OV5640_PID (0x56)
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
@@ -27,23 +29,45 @@ typedef enum {
|
||||
} pixformat_t;
|
||||
|
||||
typedef enum {
|
||||
FRAMESIZE_96x96, // 96x96
|
||||
FRAMESIZE_96X96, // 96x96
|
||||
FRAMESIZE_QQVGA, // 160x120
|
||||
FRAMESIZE_QQVGA2, // 128x160
|
||||
FRAMESIZE_QCIF, // 176x144
|
||||
FRAMESIZE_HQVGA, // 240x176
|
||||
FRAMESIZE_240x240, // 240x240
|
||||
FRAMESIZE_240X240, // 240x240
|
||||
FRAMESIZE_QVGA, // 320x240
|
||||
FRAMESIZE_CIF, // 400x296
|
||||
FRAMESIZE_HVGA, // 480x320
|
||||
FRAMESIZE_VGA, // 640x480
|
||||
FRAMESIZE_SVGA, // 800x600
|
||||
FRAMESIZE_XGA, // 1024x768
|
||||
FRAMESIZE_HD, // 1280x720
|
||||
FRAMESIZE_SXGA, // 1280x1024
|
||||
FRAMESIZE_UXGA, // 1600x1200
|
||||
FRAMESIZE_QXGA, // 2048*1536
|
||||
// 3MP Sensors
|
||||
FRAMESIZE_FHD, // 1920x1080
|
||||
FRAMESIZE_P_HD, // 720x1280
|
||||
FRAMESIZE_P_3MP, // 864x1536
|
||||
FRAMESIZE_QXGA, // 2048x1536
|
||||
// 5MP Sensors
|
||||
FRAMESIZE_QHD, // 2560x1440
|
||||
FRAMESIZE_WQXGA, // 2560x1600
|
||||
FRAMESIZE_P_FHD, // 1080x1920
|
||||
FRAMESIZE_QSXGA, // 2560x1920
|
||||
FRAMESIZE_INVALID
|
||||
} framesize_t;
|
||||
|
||||
typedef enum {
|
||||
ASPECT_RATIO_4X3,
|
||||
ASPECT_RATIO_3X2,
|
||||
ASPECT_RATIO_16X10,
|
||||
ASPECT_RATIO_5X3,
|
||||
ASPECT_RATIO_16X9,
|
||||
ASPECT_RATIO_21X9,
|
||||
ASPECT_RATIO_5X4,
|
||||
ASPECT_RATIO_1X1,
|
||||
ASPECT_RATIO_9X16
|
||||
} aspect_ratio_t;
|
||||
|
||||
typedef enum {
|
||||
GAINCEILING_2X,
|
||||
GAINCEILING_4X,
|
||||
@@ -54,6 +78,28 @@ typedef enum {
|
||||
GAINCEILING_128X,
|
||||
} gainceiling_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t max_width;
|
||||
uint16_t max_height;
|
||||
uint16_t start_x;
|
||||
uint16_t start_y;
|
||||
uint16_t end_x;
|
||||
uint16_t end_y;
|
||||
uint16_t offset_x;
|
||||
uint16_t offset_y;
|
||||
uint16_t total_x;
|
||||
uint16_t total_y;
|
||||
} ratio_settings_t;
|
||||
|
||||
typedef struct {
|
||||
const uint16_t width;
|
||||
const uint16_t height;
|
||||
const aspect_ratio_t aspect_ratio;
|
||||
} resolution_info_t;
|
||||
|
||||
// Resolution table (in sensor.c)
|
||||
extern const resolution_info_t resolution[];
|
||||
|
||||
typedef struct {
|
||||
uint8_t MIDH;
|
||||
uint8_t MIDL;
|
||||
@@ -63,6 +109,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
framesize_t framesize;//0 - 10
|
||||
bool scale;
|
||||
bool binning;
|
||||
uint8_t quality;//0 - 63
|
||||
int8_t brightness;//-2 - 2
|
||||
int8_t contrast;//-2 - 2
|
||||
@@ -132,9 +180,12 @@ typedef struct _sensor {
|
||||
|
||||
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
||||
int (*set_lenc) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*get_reg) (sensor_t *sensor, int reg, int mask);
|
||||
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
|
||||
int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning);
|
||||
int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
|
||||
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
|
||||
} sensor_t;
|
||||
|
||||
// Resolution table (in camera.c)
|
||||
extern const int resolution[][2];
|
||||
|
||||
#endif /* __SENSOR_H__ */
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "sensor.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/lldesc.h"
|
||||
#else
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
static const char* TAG = "sccb";
|
||||
#endif
|
||||
|
||||
//#undef CONFIG_SCCB_HARDWARE_I2C
|
||||
|
||||
#define LITTLETOBIG(x) ((x<<8)|(x>>8))
|
||||
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
#include "sensor.h"
|
||||
|
||||
const int resolution[][2] = {
|
||||
{ 96, 96 }, /* 96x96 */
|
||||
{ 160, 120 }, /* QQVGA */
|
||||
{ 128, 160 }, /* QQVGA2*/
|
||||
{ 176, 144 }, /* QCIF */
|
||||
{ 240, 176 }, /* HQVGA */
|
||||
{ 240, 240 }, /* 240x240 */
|
||||
{ 320, 240 }, /* QVGA */
|
||||
{ 400, 296 }, /* CIF */
|
||||
{ 640, 480 }, /* VGA */
|
||||
{ 800, 600 }, /* SVGA */
|
||||
{ 1024, 768 }, /* XGA */
|
||||
{ 1280, 1024 }, /* SXGA */
|
||||
{ 1600, 1200 }, /* UXGA */
|
||||
{ 2048, 1536 }, /* QXGA */
|
||||
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||
{ 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */
|
||||
{ 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */
|
||||
{ 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */
|
||||
{ 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */
|
||||
{ 240, 240, ASPECT_RATIO_1X1 }, /* 240x240 */
|
||||
{ 320, 240, ASPECT_RATIO_4X3 }, /* QVGA */
|
||||
{ 400, 296, ASPECT_RATIO_4X3 }, /* CIF */
|
||||
{ 480, 320, ASPECT_RATIO_3X2 }, /* HVGA */
|
||||
{ 640, 480, ASPECT_RATIO_4X3 }, /* VGA */
|
||||
{ 800, 600, ASPECT_RATIO_4X3 }, /* SVGA */
|
||||
{ 1024, 768, ASPECT_RATIO_4X3 }, /* XGA */
|
||||
{ 1280, 720, ASPECT_RATIO_16X9 }, /* HD */
|
||||
{ 1280, 1024, ASPECT_RATIO_5X4 }, /* SXGA */
|
||||
{ 1600, 1200, ASPECT_RATIO_4X3 }, /* UXGA */
|
||||
// 3MP Sensors
|
||||
{ 1920, 1080, ASPECT_RATIO_16X9 }, /* FHD */
|
||||
{ 720, 1280, ASPECT_RATIO_9X16 }, /* Portrait HD */
|
||||
{ 864, 1536, ASPECT_RATIO_9X16 }, /* Portrait 3MP */
|
||||
{ 2048, 1536, ASPECT_RATIO_4X3 }, /* QXGA */
|
||||
// 5MP Sensors
|
||||
{ 2560, 1440, ASPECT_RATIO_16X9 }, /* QHD */
|
||||
{ 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */
|
||||
{ 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */
|
||||
{ 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */
|
||||
};
|
||||
|
||||
@@ -12,19 +12,28 @@
|
||||
static const char* TAG = "camera_xclk";
|
||||
#endif
|
||||
|
||||
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
|
||||
{
|
||||
ledc_timer_config_t timer_conf;
|
||||
timer_conf.duty_resolution = 2;
|
||||
timer_conf.freq_hz = xclk_freq_hz;
|
||||
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||
timer_conf.clk_cfg = LEDC_AUTO_CLK;
|
||||
#endif
|
||||
timer_conf.timer_num = (ledc_timer_t)ledc_timer;
|
||||
esp_err_t err = ledc_timer_config(&timer_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed for freq %d, rc=%x", xclk_freq_hz, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t camera_enable_out_clock(camera_config_t* config)
|
||||
{
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
|
||||
ledc_timer_config_t timer_conf = {};
|
||||
timer_conf.duty_resolution = 2;
|
||||
timer_conf.freq_hz = config->xclk_freq_hz;
|
||||
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
timer_conf.timer_num = config->ledc_timer;
|
||||
#ifdef ESP_IDF_VERSION_MAJOR
|
||||
timer_conf.clk_cfg = LEDC_AUTO_CLK;
|
||||
#endif
|
||||
esp_err_t err = ledc_timer_config(&timer_conf);
|
||||
esp_err_t err = xclk_timer_conf(config->ledc_timer, config->xclk_freq_hz);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user