Add support for Hardware I2C and OV3660
This commit is contained in:
118
driver/camera.c
118
driver/camera.c
@@ -40,12 +40,16 @@
|
||||
#if CONFIG_OV7725_SUPPORT
|
||||
#include "ov7725.h"
|
||||
#endif
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
#include "ov3660.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CAMERA_NONE = 0,
|
||||
CAMERA_UNKNOWN = 1,
|
||||
CAMERA_OV7725 = 7725,
|
||||
CAMERA_OV2640 = 2640,
|
||||
CAMERA_OV3660 = 3660,
|
||||
} camera_model_t;
|
||||
|
||||
#define REG_PID 0x0A
|
||||
@@ -53,6 +57,9 @@ typedef enum {
|
||||
#define REG_MIDH 0x1C
|
||||
#define REG_MIDL 0x1D
|
||||
|
||||
#define REG16_CHIDH 0x300A
|
||||
#define REG16_CHIDL 0x300B
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define TAG ""
|
||||
@@ -119,7 +126,7 @@ typedef struct {
|
||||
camera_state_t* s_state = NULL;
|
||||
|
||||
static void i2s_init();
|
||||
static void i2s_run();
|
||||
static int i2s_run();
|
||||
static void IRAM_ATTR vsync_isr(void* arg);
|
||||
static void IRAM_ATTR i2s_isr(void* arg);
|
||||
static esp_err_t dma_desc_init();
|
||||
@@ -171,20 +178,32 @@ static void vsync_intr_enable()
|
||||
gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_NEGEDGE);
|
||||
}
|
||||
|
||||
static void skip_frame()
|
||||
static int skip_frame()
|
||||
{
|
||||
if (s_state == NULL) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
int64_t st_t = esp_timer_get_time();
|
||||
while (_gpio_get_level(s_state->config.pin_vsync) == 0) {
|
||||
;
|
||||
if((esp_timer_get_time() - st_t) > 1000000LL){
|
||||
goto timeout;
|
||||
}
|
||||
}
|
||||
while (_gpio_get_level(s_state->config.pin_vsync) != 0) {
|
||||
;
|
||||
if((esp_timer_get_time() - st_t) > 1000000LL){
|
||||
goto timeout;
|
||||
}
|
||||
}
|
||||
while (_gpio_get_level(s_state->config.pin_vsync) == 0) {
|
||||
;
|
||||
if((esp_timer_get_time() - st_t) > 1000000LL){
|
||||
goto timeout;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
timeout:
|
||||
ESP_LOGE(TAG, "Timeout waiting for VSYNC");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void camera_fb_deinit()
|
||||
@@ -448,7 +467,7 @@ static void IRAM_ATTR i2s_start_bus()
|
||||
}
|
||||
}
|
||||
|
||||
static void i2s_run()
|
||||
static int i2s_run()
|
||||
{
|
||||
for (int i = 0; i < s_state->dma_desc_count; ++i) {
|
||||
lldesc_t* d = &s_state->dma_desc[i];
|
||||
@@ -469,14 +488,19 @@ static void i2s_run()
|
||||
vTaskDelay(2);
|
||||
}
|
||||
|
||||
// wait for vsync
|
||||
//todo: wait for vsync
|
||||
ESP_LOGV(TAG, "Waiting for negative edge on VSYNC");
|
||||
|
||||
int64_t st_t = esp_timer_get_time();
|
||||
while (_gpio_get_level(s_state->config.pin_vsync) != 0) {
|
||||
;
|
||||
if((esp_timer_get_time() - st_t) > 1000000LL){
|
||||
ESP_LOGE(TAG, "Timeout waiting for VSYNC");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "Got VSYNC");
|
||||
|
||||
i2s_start_bus();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2s_stop_bus()
|
||||
@@ -890,13 +914,25 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
ESP_LOGD(TAG, "Detected camera at address=0x%02x", s_state->sensor.slv_addr);
|
||||
sensor_id_t* id = &s_state->sensor.id;
|
||||
|
||||
id->PID = SCCB_Read(s_state->sensor.slv_addr, REG_PID);
|
||||
id->VER = SCCB_Read(s_state->sensor.slv_addr, REG_VER);
|
||||
id->MIDL = SCCB_Read(s_state->sensor.slv_addr, REG_MIDL);
|
||||
id->MIDH = SCCB_Read(s_state->sensor.slv_addr, REG_MIDH);
|
||||
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(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);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x", id->PID, id->VER);
|
||||
} else {
|
||||
#endif
|
||||
id->PID = SCCB_Read(s_state->sensor.slv_addr, REG_PID);
|
||||
id->VER = SCCB_Read(s_state->sensor.slv_addr, REG_VER);
|
||||
id->MIDL = SCCB_Read(s_state->sensor.slv_addr, REG_MIDL);
|
||||
id->MIDH = SCCB_Read(s_state->sensor.slv_addr, REG_MIDH);
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
switch (id->PID) {
|
||||
#if CONFIG_OV2640_SUPPORT
|
||||
@@ -910,6 +946,12 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
|
||||
*out_camera_model = CAMERA_OV7725;
|
||||
ov7725_init(&s_state->sensor);
|
||||
break;
|
||||
#endif
|
||||
#if CONFIG_OV3660_SUPPORT
|
||||
case OV3660_PID:
|
||||
*out_camera_model = CAMERA_OV3660;
|
||||
ov3660_init(&s_state->sensor);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
id->PID = 0;
|
||||
@@ -942,14 +984,25 @@ esp_err_t camera_init(const camera_config_t* config)
|
||||
|
||||
if (pix_format == PIXFORMAT_GRAYSCALE) {
|
||||
s_state->fb_size = s_state->width * s_state->height;
|
||||
if (is_hs_mode()) {
|
||||
s_state->sampling_mode = SM_0A00_0B00;
|
||||
s_state->dma_filter = &dma_filter_grayscale_highspeed;
|
||||
if (s_state->sensor.id.PID == OV3660_PID) {
|
||||
if (is_hs_mode()) {
|
||||
s_state->sampling_mode = SM_0A00_0B00;
|
||||
s_state->dma_filter = &dma_filter_yuyv_highspeed;
|
||||
} else {
|
||||
s_state->sampling_mode = SM_0A0B_0C0D;
|
||||
s_state->dma_filter = &dma_filter_yuyv;
|
||||
}
|
||||
s_state->in_bytes_per_pixel = 1; // camera sends Y8
|
||||
} else {
|
||||
s_state->sampling_mode = SM_0A0B_0C0D;
|
||||
s_state->dma_filter = &dma_filter_grayscale;
|
||||
if (is_hs_mode()) {
|
||||
s_state->sampling_mode = SM_0A00_0B00;
|
||||
s_state->dma_filter = &dma_filter_grayscale_highspeed;
|
||||
} else {
|
||||
s_state->sampling_mode = SM_0A0B_0C0D;
|
||||
s_state->dma_filter = &dma_filter_grayscale;
|
||||
}
|
||||
s_state->in_bytes_per_pixel = 2; // camera sends YU/YV
|
||||
}
|
||||
s_state->in_bytes_per_pixel = 2; // camera sends YUYV
|
||||
s_state->fb_bytes_per_pixel = 1; // frame buffer stores Y8
|
||||
} else if (pix_format == PIXFORMAT_YUV422 || pix_format == PIXFORMAT_RGB565) {
|
||||
s_state->fb_size = s_state->width * s_state->height * 2;
|
||||
@@ -960,11 +1013,11 @@ esp_err_t camera_init(const camera_config_t* config)
|
||||
s_state->sampling_mode = SM_0A0B_0C0D;
|
||||
s_state->dma_filter = &dma_filter_yuyv;
|
||||
}
|
||||
s_state->in_bytes_per_pixel = 2; // camera sends YUYV
|
||||
s_state->fb_bytes_per_pixel = 2; // frame buffer stores Y8
|
||||
s_state->in_bytes_per_pixel = 2; // camera sends YU/YV
|
||||
s_state->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
|
||||
} else if (pix_format == PIXFORMAT_JPEG) {
|
||||
if (s_state->sensor.id.PID != OV2640_PID) {
|
||||
ESP_LOGE(TAG, "JPEG format is only supported for ov2640");
|
||||
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");
|
||||
err = ESP_ERR_NOT_SUPPORTED;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1065,7 +1118,10 @@ esp_err_t camera_init(const camera_config_t* config)
|
||||
s_state->sensor.set_lenc(&s_state->sensor, true);
|
||||
}
|
||||
|
||||
skip_frame();
|
||||
if (skip_frame()) {
|
||||
err = ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT;
|
||||
goto fail;
|
||||
}
|
||||
//todo: for some reason the first set of the quality does not work.
|
||||
if (pix_format == PIXFORMAT_JPEG) {
|
||||
(*s_state->sensor.set_quality)(&s_state->sensor, config->jpeg_quality);
|
||||
@@ -1095,6 +1151,8 @@ esp_err_t esp_camera_init(const camera_config_t* config)
|
||||
}
|
||||
} else if (camera_model == CAMERA_OV2640) {
|
||||
ESP_LOGD(TAG, "Detected OV2640 camera");
|
||||
} else if (camera_model == CAMERA_OV3660) {
|
||||
ESP_LOGD(TAG, "Detected OV3660 camera");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Camera not supported");
|
||||
err = ESP_ERR_CAMERA_NOT_SUPPORTED;
|
||||
@@ -1157,7 +1215,9 @@ camera_fb_t* esp_camera_fb_get()
|
||||
if(s_state->config.fb_count > 1) {
|
||||
ESP_LOGD(TAG, "i2s_run");
|
||||
}
|
||||
i2s_run();
|
||||
if (i2s_run() != 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(s_state->config.fb_count == 1) {
|
||||
xSemaphoreTake(s_state->frame_ready, portMAX_DELAY);
|
||||
|
||||
@@ -120,7 +120,8 @@ typedef struct {
|
||||
#define ESP_ERR_CAMERA_BASE 0x20000
|
||||
#define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2)
|
||||
#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 3)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3)
|
||||
#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4)
|
||||
|
||||
/**
|
||||
* @brief Initialize the camera driver
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define OV9650_PID (0x96)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV7725_PID (0x77)
|
||||
#define OV3660_PID (0x36)
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
@@ -20,6 +21,9 @@ typedef enum {
|
||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||
PIXFORMAT_RAW, // RAW
|
||||
PIXFORMAT_RGB444, // 3BP2P/RGB444
|
||||
PIXFORMAT_RGB555, // 3BP2P/RGB555
|
||||
} pixformat_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -34,6 +38,8 @@ typedef enum {
|
||||
FRAMESIZE_XGA, // 1024x768
|
||||
FRAMESIZE_SXGA, // 1280x1024
|
||||
FRAMESIZE_UXGA, // 1600x1200
|
||||
FRAMESIZE_QXGA, // 2048*1536
|
||||
FRAMESIZE_INVALID
|
||||
} framesize_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -59,6 +65,8 @@ typedef struct {
|
||||
int8_t brightness;//-2 - 2
|
||||
int8_t contrast;//-2 - 2
|
||||
int8_t saturation;//-2 - 2
|
||||
int8_t sharpness;//-2 - 2
|
||||
uint8_t denoise;
|
||||
uint8_t special_effect;//0 - 6
|
||||
uint8_t wb_mode;//0 - 4
|
||||
uint8_t awb;
|
||||
@@ -96,6 +104,8 @@ typedef struct _sensor {
|
||||
int (*set_contrast) (sensor_t *sensor, int level);
|
||||
int (*set_brightness) (sensor_t *sensor, int level);
|
||||
int (*set_saturation) (sensor_t *sensor, int level);
|
||||
int (*set_sharpness) (sensor_t *sensor, int level);
|
||||
int (*set_denoise) (sensor_t *sensor, int level);
|
||||
int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
|
||||
int (*set_quality) (sensor_t *sensor, int quality);
|
||||
int (*set_colorbar) (sensor_t *sensor, int enable);
|
||||
@@ -120,6 +130,9 @@ typedef struct _sensor {
|
||||
|
||||
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
||||
int (*set_lenc) (sensor_t *sensor, int enable);
|
||||
|
||||
// Advanced functions
|
||||
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
|
||||
} sensor_t;
|
||||
|
||||
// Resolution table (in camera.c)
|
||||
|
||||
@@ -13,4 +13,6 @@ int SCCB_Init(int pin_sda, int pin_scl);
|
||||
uint8_t SCCB_Probe();
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data);
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg);
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data);
|
||||
#endif // __SCCB_H__
|
||||
|
||||
184
driver/sccb.c
184
driver/sccb.c
@@ -10,7 +10,6 @@
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "sccb.h"
|
||||
#include "twi.h"
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
@@ -20,38 +19,107 @@
|
||||
static const char* TAG = "sccb";
|
||||
#endif
|
||||
|
||||
#define LITTLETOBIG(x) ((x<<8)|(x>>8))
|
||||
|
||||
#define SCCB_FREQ (100000) // We don't need fast I2C. 100KHz is fine here.
|
||||
#define TIMEOUT (1000) /* Can't be sure when I2C routines return. Interrupts
|
||||
while polling hardware may result in unknown delays. */
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#define SCCB_FREQ 200000 /*!< I2C master frequency*/
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
const int SCCB_I2C_PORT = 1;
|
||||
static uint8_t ESP_SLAVE_ADDR = 0x3c;
|
||||
#else
|
||||
#include "twi.h"
|
||||
#endif
|
||||
|
||||
int SCCB_Init(int pin_sda, int pin_scl)
|
||||
{
|
||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d\n", pin_sda, pin_scl);
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
log_i("SCCB_Init start");
|
||||
i2c_config_t conf;
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = pin_sda;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.scl_io_num = pin_scl;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = SCCB_FREQ;
|
||||
|
||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
||||
#else
|
||||
twi_init(pin_sda, pin_scl);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Probe()
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t slave_addr = 0x0;
|
||||
while(slave_addr < 0x7f) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if( ret == ESP_OK) {
|
||||
ESP_SLAVE_ADDR = slave_addr;
|
||||
return ESP_SLAVE_ADDR;
|
||||
}
|
||||
slave_addr++;
|
||||
}
|
||||
return ESP_SLAVE_ADDR;
|
||||
#else
|
||||
uint8_t reg = 0x00;
|
||||
uint8_t slv_addr = 0x00;
|
||||
|
||||
for (uint8_t i=0; i<127; i++) {
|
||||
ESP_LOGI(TAG, "SCCB_Probe start");
|
||||
for (uint8_t i = 0; i < 127; i++) {
|
||||
if (twi_writeTo(i, ®, 1, true) == 0) {
|
||||
slv_addr = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i!=126) {
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // Necessary for OV7725 camera (not for OV2640).
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Necessary for OV7725 camera (not for OV2640).
|
||||
}
|
||||
}
|
||||
return slv_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", ESP_SLAVE_ADDR, reg, data, ret);
|
||||
}
|
||||
return data;
|
||||
#else
|
||||
uint8_t data=0;
|
||||
|
||||
int rc = twi_writeTo(slv_addr, ®, 1, true);
|
||||
@@ -67,10 +135,26 @@ uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
ESP_LOGE(TAG, "SCCB_Read [%02x] failed rc=%d\n", reg, rc);
|
||||
}
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", ESP_SLAVE_ADDR, reg, data, ret);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
#else
|
||||
uint8_t ret=0;
|
||||
uint8_t buf[] = {reg, data};
|
||||
|
||||
@@ -78,7 +162,93 @@ uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
ret=0xFF;
|
||||
}
|
||||
if (ret != 0) {
|
||||
printf("SCCB_Write [%02x]=%02x failed\n", reg, data);
|
||||
ESP_LOGE(TAG, "SCCB_Write [%02x]=%02x failed\n", reg, data);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
||||
}
|
||||
return data;
|
||||
#else
|
||||
uint8_t data=0;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
uint8_t buf[] = {reg_u8[0], reg_u8[1]};
|
||||
|
||||
int rc = twi_writeTo(slv_addr, buf, 2, true);
|
||||
if (rc != 0) {
|
||||
data = 0xff;
|
||||
} else {
|
||||
rc = twi_readFrom(slv_addr, &data, 1, true);
|
||||
if (rc != 0) {
|
||||
data=0xFF;
|
||||
}
|
||||
}
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "R [%04x] fail rc=%d\n", reg, rc);
|
||||
}
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
|
||||
{
|
||||
static uint16_t i = 0;
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
#else
|
||||
uint8_t ret=0;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
uint8_t buf[] = {reg_u8[0], reg_u8[1], data};
|
||||
|
||||
if(twi_writeTo(slv_addr, buf, 3, true) != 0) {
|
||||
ret = 0xFF;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const int resolution[][2] = {
|
||||
{ 1024, 768 }, /* XGA */
|
||||
{ 1280, 1024 }, /* SXGA */
|
||||
{ 1600, 1200 }, /* UXGA */
|
||||
{ 2048, 1536 }, /* QXGA */
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user