diff --git a/.gitignore b/.gitignore index f39d5fd..60e365a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ **/build **/sdkconfig **/sdkconfig.old -**/dependencies.lock \ No newline at end of file +**/dependencies.lock diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ebc992..ccfbceb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}") # set conversion sources -set(srcs +set(COMPONENT_SRCS conversions/yuv.c conversions/to_jpg.cpp conversions/to_bmp.c @@ -10,11 +10,11 @@ set(srcs conversions/esp_jpg_decode.c ) -set(priv_include_dirs +set(COMPONENT_PRIV_INCLUDEDIRS conversions/private_include ) -set(include_dirs +set(COMPONENT_ADD_INCLUDEDIRS driver/include conversions/include ) @@ -23,9 +23,10 @@ set(COMPONENT_REQUIRES driver) # set driver sources only for supported platforms if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3") - list(APPEND srcs + list(APPEND COMPONENT_SRCS driver/esp_camera.c driver/cam_hal.c + driver/sccb.c driver/sensor.c sensors/ov2640.c sensors/ov3660.c @@ -44,51 +45,42 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST sensors/mega_ccm.c ) - list(APPEND priv_include_dirs + list(APPEND COMPONENT_PRIV_INCLUDEDIRS driver/private_include sensors/private_include target/private_include ) if(IDF_TARGET STREQUAL "esp32") - list(APPEND srcs + list(APPEND COMPONENT_SRCS target/xclk.c target/esp32/ll_cam.c ) endif() if(IDF_TARGET STREQUAL "esp32s2") - list(APPEND srcs + list(APPEND COMPONENT_SRCS target/xclk.c target/esp32s2/ll_cam.c target/tjpgd.c ) - list(APPEND priv_include_dirs + list(APPEND COMPONENT_PRIV_INCLUDEDIRS target/esp32s2/private_include ) endif() if(IDF_TARGET STREQUAL "esp32s3") - list(APPEND srcs + list(APPEND COMPONENT_SRCS target/esp32s3/ll_cam.c ) endif() - set(priv_requires freertos nvs_flash) + set(COMPONENT_PRIV_REQUIRES freertos nvs_flash) set(min_version_for_esp_timer "4.2") if (idf_version VERSION_GREATER_EQUAL min_version_for_esp_timer) - list(APPEND priv_requires esp_timer) - endif() - - # include the SCCB I2C driver - # this uses either the legacy I2C API or the newwer version from IDF v5.4 - # as this features a method to obtain the I2C driver from a port number - if (idf_version VERSION_GREATER_EQUAL "5.4") - list(APPEND srcs driver/sccb-ng.c) - else() - list(APPEND srcs driver/sccb.c) + list(APPEND COMPONENT_PRIV_REQUIRES esp_timer) endif() endif() @@ -96,18 +88,12 @@ endif() # CONFIG_ESP_ROM_HAS_JPEG_DECODE is available from IDF v4.4 but # previous IDF supported chips already support JPEG decoder, hence okay to use this if(idf_version VERSION_GREATER_EQUAL "4.4" AND NOT CONFIG_ESP_ROM_HAS_JPEG_DECODE) - list(APPEND srcs + list(APPEND COMPONENT_SRCS target/tjpgd.c ) - list(APPEND priv_include_dirs + list(APPEND COMPONENT_PRIV_INCLUDEDIRS target/jpeg_include/ ) endif() -idf_component_register( - SRCS ${srcs} - INCLUDE_DIRS ${include_dirs} - PRIV_INCLUDE_DIRS ${priv_include_dirs} - REQUIRES driver # due to include of driver/gpio.h in esp_camera.h - PRIV_REQUIRES ${priv_requires} -) +register_component() diff --git a/Kconfig b/Kconfig index 2285e43..e8006c3 100755 --- a/Kconfig +++ b/Kconfig @@ -1,5 +1,4 @@ menu "Camera configuration" - config OV7670_SUPPORT bool "Support OV7670 VGA" default y @@ -118,12 +117,12 @@ menu "Camera configuration" Disable this option to save memory. config MEGA_CCM_SUPPORT - bool "Support MEGA CCM 5MP" - default y + bool "Support MEGA_CCM 5MP" + default n help - Enable this option if you want to use the MEGA CCM. + Enable this option if you want to use the MEGA_CCM. Disable this option to save memory. - + choice SCCB_HARDWARE_I2C_PORT bool "I2C peripheral to use for SCCB" default SCCB_HARDWARE_I2C_PORT1 @@ -137,8 +136,8 @@ menu "Camera configuration" config SCCB_CLK_FREQ int "SCCB clk frequency" - default 100000 - range 100000 400000 + default 1000 + range 1000 400000 help Increasing this value can reduce the initialization time of the sensor. Please refer to the relevant instructions of the sensor to adjust the value. @@ -186,33 +185,6 @@ menu "Camera configuration" Maximum value of DMA buffer Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent. - choice CAMERA_JPEG_MODE_FRAME_SIZE_OPTION - prompt "JPEG mode frame size option" - default CAMERA_JPEG_MODE_FRAME_SIZE_AUTO - help - Select whether to use automatic calculation for JPEG mode frame size or specify a custom value. - - config CAMERA_JPEG_MODE_FRAME_SIZE_AUTO - bool "Use automatic calculation (width * height / 5)" - help - Use the default calculation for JPEG mode frame size. - Note: In very low resolutions like QQVGA, the default calculation tends to result in insufficient buffer size. - - config CAMERA_JPEG_MODE_FRAME_SIZE_CUSTOM - bool "Specify custom frame size" - help - Specify a custom frame size in bytes for JPEG mode. - - endchoice - - config CAMERA_JPEG_MODE_FRAME_SIZE - int "Custom JPEG mode frame size (bytes)" - default 8192 - depends on CAMERA_JPEG_MODE_FRAME_SIZE_CUSTOM - help - This option sets the custom frame size in JPEG mode. - Specify the desired buffer size in bytes. - config CAMERA_CONVERTER_ENABLED bool "Enable camera RGB/YUV converter" depends on IDF_TARGET_ESP32S3 @@ -244,11 +216,6 @@ menu "Camera configuration" Full color range mode has a wider color range, so details in the image show more clearly. Please confirm the color range mode of the current camera sensor, incorrect color range mode may cause color difference in the final converted image. Full range mode is used by default. If this option is not selected, the format conversion function will be done using the limited range mode. - - config LCD_CAM_ISR_IRAM_SAFE - bool "Execute camera ISR from IRAM" - depends on (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3) - default n - help - If this option is enabled, camera ISR will execute from IRAM. endmenu + + diff --git a/README.md b/README.md index 092f893..46a3f80 100644 --- a/README.md +++ b/README.md @@ -1,359 +1,132 @@ -# ESP32 Camera Driver +# ESP32S3 GC032A Camera Driver [![Build examples](https://github.com/espressif/esp32-camera/actions/workflows/build.yml/badge.svg)](https://github.com/espressif/esp32-camera/actions/workflows/build.yml) [![Component Registry](https://components.espressif.com/components/espressif/esp32-camera/badge.svg)](https://components.espressif.com/components/espressif/esp32-camera) -## General Information - -This repository hosts ESP32 series Soc compatible driver for image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats. ### Supported Soc -- ESP32 -- ESP32-S2 - ESP32-S3 ### Supported Sensor -| model | max resolution | color type | output format | Len Size | -| ------- | -------------- | ---------- | ------------------------------------------------------------ | -------- | -| OV2640 | 1600 x 1200 | color | YUV(422/420)/YCbCr422
RGB565/555
8-bit compressed data
8/10-bit Raw RGB data | 1/4" | -| OV3660 | 2048 x 1536 | color | raw RGB data
RGB565/555/444
CCIR656
YCbCr422
compression | 1/5" | -| OV5640 | 2592 x 1944 | color | RAW RGB
RGB565/555/444
CCIR656
YUV422/420
YCbCr422
compression | 1/4" | -| OV7670 | 640 x 480 | color | Raw Bayer RGB
Processed Bayer RGB
YUV/YCbCr422
GRB422
RGB565/555 | 1/6" | -| OV7725 | 640 x 480 | color | Raw RGB
GRB 422
RGB565/555/444
YCbCr 422 | 1/4" | -| NT99141 | 1280 x 720 | color | YCbCr 422
RGB565/555/444
Raw
CCIR656
JPEG compression | 1/4" | -| GC032A | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/10" | -| GC0308 | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565
Grayscale | 1/6.5" | -| GC2145 | 1600 x 1200 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/5" | -| BF3005 | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/4" | -| BF20A6 | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
Only Y | 1/10" | -| SC101IOT| 1280 x 720 | color | YUV/YCbCr422
Raw RGB | 1/4.2" | -| SC030IOT| 640 x 480 | color | YUV/YCbCr422
RAW Bayer | 1/6.5" | -| SC031GS | 640 x 480 | monochrome | RAW MONO
Grayscale | 1/6" | - -## Important to Remember +| model | max resolution | color type | output format | +| ------ | -------------- | ---------- | ---------------- | +| GC032A | 640 x 480 | color | YCbCr422 /RGB565 | -- Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated. -- Using YUV or RGB puts a lot of strain on the chip because writing to PSRAM is not particularly fast. The result is that image data might be missing. This is particularly true if WiFi is enabled. If you need RGB data, it is recommended that JPEG is captured and then turned into RGB using `fmt2rgb888` or `fmt2bmp`/`frame2bmp`. -- When 1 frame buffer is used, the driver will wait for the current frame to finish (VSYNC) and start I2S DMA. After the frame is acquired, I2S will be stopped and the frame buffer returned to the application. This approach gives more control over the system, but results in longer time to get the frame. -- When 2 or more frame bufers are used, I2S is running in continuous mode and each frame is pushed to a queue that the application can access. This approach puts more strain on the CPU/Memory, but allows for double the frame rate. Please use only with JPEG. +### Factory Example Functions -## Installation Instructions +- Set gc032a camera to 640x480 RGB565 mode +- Convert RGB565 to JPEG +- Send image data from UART0 +### How to configure factory example? -### Using with ESP-IDF +- Select Octal Mode PSRAM in menuconfig + ![image](data\psram.png) +- Select GC023A sensor and i2c0 bus in menuconfig + ![image](data\demo_mecuconfig.png) -- Add a dependency on `espressif/esp32-camera` component: - ```bash - idf.py add-dependency "espressif/esp32-camera" - ``` - (or add it manually in idf_component.yml of your project) -- Enable PSRAM in `menuconfig` (also set Flash and PSRAM frequiencies to 80MHz) -- Include `esp_camera.h` in your code +### Hardware connection -These instructions also work for PlatformIO, if you are using `framework=espidf`. +#### Psv2-dev -### Using with Arduino +![image](data\psv2_dev.png) -#### Arduino IDE +![image](data\hardware_psv2_dev.png) -If you are using the arduino-esp32 core in Arduino IDE, no installation is needed! You can use esp32-camera right away. +- UART0 pin definition -#### PlatformIO +| GND | TX | RX | +| --- | -- | -- | +| GND | 43 | 44 | -The easy way -- on the `env` section of `platformio.ini`, add the following: -```ini -[env] -lib_deps = - esp32-camera -``` +- GC032A pin definition -Now the `esp_camera.h` is available to be included: - -```c -#include "esp_camera.h" -``` - -Enable PSRAM on `menuconfig` or type it direclty on `sdkconfig`. Check the [official doc](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support) for more info. - -``` -CONFIG_ESP32_SPIRAM_SUPPORT=y -``` +| GC032A | XCLK | SIOD | SIOC | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | VSYNC | HREF | +| --------- | ---- | -------- | --------- | -- | -- | -- | -- | -- | -- | -- | -- | ----- | ---- | +| ESP32S3R8 | 6 | 2 [I2C0] | 0 [I2C0] | 46 | 42 | 41 | 45 | 5 | 8 | 7 | 39 | 3 | 4 | -## Examples -This component comes with a basic example illustrating how to get frames from the camera. You can try out the example using the following command: +- I2C-SLAVE pin definition -``` -idf.py create-project-from-example "espressif/esp32-camera:camera_example" -``` +| VCC | GND | SLAVE_SDA | SLAVE_SCL | +| --- | --- | --------- | --------- | +| 3.3 | GND | 17 [I2C1] | 18 [I2C1] | -This command will download the example into `camera_example` directory. It comes already pre-configured with the correct settings in menuconfig. - -### Initialization - -```c -#include "esp_camera.h" - -//WROVER-KIT PIN Map -#define CAM_PIN_PWDN -1 //power down is not used -#define CAM_PIN_RESET -1 //software reset will be performed -#define CAM_PIN_XCLK 21 -#define CAM_PIN_SIOD 26 -#define CAM_PIN_SIOC 27 - -#define CAM_PIN_D7 35 -#define CAM_PIN_D6 34 -#define CAM_PIN_D5 39 -#define CAM_PIN_D4 36 -#define CAM_PIN_D3 19 -#define CAM_PIN_D2 18 -#define CAM_PIN_D1 5 -#define CAM_PIN_D0 4 -#define CAM_PIN_VSYNC 25 -#define CAM_PIN_HREF 23 -#define CAM_PIN_PCLK 22 - -static camera_config_t camera_config = { - .pin_pwdn = CAM_PIN_PWDN, - .pin_reset = CAM_PIN_RESET, - .pin_xclk = CAM_PIN_XCLK, - .pin_sccb_sda = CAM_PIN_SIOD, - .pin_sccb_scl = CAM_PIN_SIOC, - - .pin_d7 = CAM_PIN_D7, - .pin_d6 = CAM_PIN_D6, - .pin_d5 = CAM_PIN_D5, - .pin_d4 = CAM_PIN_D4, - .pin_d3 = CAM_PIN_D3, - .pin_d2 = CAM_PIN_D2, - .pin_d1 = CAM_PIN_D1, - .pin_d0 = CAM_PIN_D0, - .pin_vsync = CAM_PIN_VSYNC, - .pin_href = CAM_PIN_HREF, - .pin_pclk = CAM_PIN_PCLK, - - .xclk_freq_hz = 20000000,//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode - .ledc_timer = LEDC_TIMER_0, - .ledc_channel = LEDC_CHANNEL_0, - - .pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG - .frame_size = FRAMESIZE_UXGA,//QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates. - - .jpeg_quality = 12, //0-63, for OV series camera sensors, lower number means higher quality - .fb_count = 1, //When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode. - .grab_mode = CAMERA_GRAB_WHEN_EMPTY//CAMERA_GRAB_LATEST. Sets when buffers should be filled -}; - -esp_err_t camera_init(){ - //power up the camera if PWDN pin is defined - if(CAM_PIN_PWDN != -1){ - pinMode(CAM_PIN_PWDN, OUTPUT); - digitalWrite(CAM_PIN_PWDN, LOW); - } +#### Psv2-1.0 - //initialize the camera - esp_err_t err = esp_camera_init(&camera_config); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Camera Init Failed"); - return err; - } +![image](data\hardware_psv2_1.0.png) +![image](data\psv2_1.0.png) - return ESP_OK; -} +- UART0 pin definition -esp_err_t camera_capture(){ - //acquire a frame - camera_fb_t * fb = esp_camera_fb_get(); - if (!fb) { - ESP_LOGE(TAG, "Camera Capture Failed"); - return ESP_FAIL; - } - //replace this with your own function - process_image(fb->width, fb->height, fb->format, fb->buf, fb->len); - - //return the frame buffer back to the driver for reuse - esp_camera_fb_return(fb); - return ESP_OK; -} -``` +| GND | TX | RX | +| --- | -- | -- | +| GND | 43 | 44 | -### JPEG HTTP Capture -```c -#include "esp_camera.h" -#include "esp_http_server.h" -#include "esp_timer.h" +- GC032A pin definition -typedef struct { - httpd_req_t *req; - size_t len; -} jpg_chunking_t; +| GC032A | XCLK | SIOD | SIOC | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | VSYNC | HREF | RST | +| --------- | ---- | -------- | --------- | -- | -- | -- | -- | -- | -- | -- | -- | ----- | ---- | --- | +| ESP32S3R8 | 41 | 1 [I2C0] | 2 [I2C0] | 5 | 6 | 4 | 46 | 45 | 42 | 39 | 40 | 4 | 3 | 8 | -static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ - jpg_chunking_t *j = (jpg_chunking_t *)arg; - if(!index){ - j->len = 0; - } - if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){ - return 0; - } - j->len += len; - return len; -} -esp_err_t jpg_httpd_handler(httpd_req_t *req){ - camera_fb_t * fb = NULL; - esp_err_t res = ESP_OK; - size_t fb_len = 0; - int64_t fr_start = esp_timer_get_time(); - - fb = esp_camera_fb_get(); - if (!fb) { - ESP_LOGE(TAG, "Camera capture failed"); - httpd_resp_send_500(req); - return ESP_FAIL; - } - res = httpd_resp_set_type(req, "image/jpeg"); - if(res == ESP_OK){ - res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg"); - } +- I2C-SLAVE pin definition - if(res == ESP_OK){ - if(fb->format == PIXFORMAT_JPEG){ - fb_len = fb->len; - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } else { - jpg_chunking_t jchunk = {req, 0}; - res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; - httpd_resp_send_chunk(req, NULL, 0); - fb_len = jchunk.len; - } - } - esp_camera_fb_return(fb); - int64_t fr_end = esp_timer_get_time(); - ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000)); - return res; -} -``` +| VCC | GND | SLAVE_SDA | SLAVE_SCL | +| --- | --- | --------- | --------- | +| 3.3 | GND | 17 [I2C1] | 18 [I2C1] | -### JPEG HTTP Stream - -```c -#include "esp_camera.h" -#include "esp_http_server.h" -#include "esp_timer.h" - -#define PART_BOUNDARY "123456789000000000000987654321" -static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; -static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; -static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; - -esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){ - camera_fb_t * fb = NULL; - esp_err_t res = ESP_OK; - size_t _jpg_buf_len; - uint8_t * _jpg_buf; - char * part_buf[64]; - static int64_t last_frame = 0; - if(!last_frame) { - last_frame = esp_timer_get_time(); - } +### Sample test - res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); - if(res != ESP_OK){ - return res; - } +- Download host app + https://github.com/ArduCAM/Arducam_mini/releases/download/v1.0.1/ArduCAM_Host_V2.0_Windows.rar +- Test (select right serial port baudrate: 921600) + ![image](data\demo.png) - while(true){ - fb = esp_camera_fb_get(); - if (!fb) { - ESP_LOGE(TAG, "Camera capture failed"); - res = ESP_FAIL; - break; - } - if(fb->format != PIXFORMAT_JPEG){ - bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); - if(!jpeg_converted){ - ESP_LOGE(TAG, "JPEG compression failed"); - esp_camera_fb_return(fb); - res = ESP_FAIL; - } - } else { - _jpg_buf_len = fb->len; - _jpg_buf = fb->buf; - } - - if(res == ESP_OK){ - res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); - } - if(res == ESP_OK){ - size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len); - - res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); - } - if(res == ESP_OK){ - res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len); - } - if(fb->format != PIXFORMAT_JPEG){ - free(_jpg_buf); - } - esp_camera_fb_return(fb); - if(res != ESP_OK){ - break; - } - int64_t fr_end = esp_timer_get_time(); - int64_t frame_time = fr_end - last_frame; - last_frame = fr_end; - frame_time /= 1000; - ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)", - (uint32_t)(_jpg_buf_len/1024), - (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time); - } +### Write I2C-SLAVE (7bits address: 0x0C) - last_frame = 0; - return res; +```bash +* ___________________________________________________________________ +* | start | slave_addr + wr_bit + ack | write n bytes + ack | stop | +* --------|---------------------------|----------------------|------| +* +static esp_err_t __attribute__((unused)) i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size) +{ + 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(cmd, data_wr, size, ACK_CHECK_EN); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + return ret; } ``` -### BMP HTTP Capture - -```c -#include "esp_camera.h" -#include "esp_http_server.h" -#include "esp_timer.h" - -esp_err_t bmp_httpd_handler(httpd_req_t *req){ - camera_fb_t * fb = NULL; - esp_err_t res = ESP_OK; - int64_t fr_start = esp_timer_get_time(); - - fb = esp_camera_fb_get(); - if (!fb) { - ESP_LOGE(TAG, "Camera capture failed"); - httpd_resp_send_500(req); - return ESP_FAIL; +### Read I2C-SLAVE + +```bash + *_______________________________________________________________________________________ + * | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop | + * --------|--------------------------|----------------------|--------------------|------| + * + static esp_err_t __attribute__((unused)) i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size) +{ + if (size == 0) { + return ESP_OK; } - - uint8_t * buf = NULL; - size_t buf_len = 0; - bool converted = frame2bmp(fb, &buf, &buf_len); - esp_camera_fb_return(fb); - if(!converted){ - ESP_LOGE(TAG, "BMP conversion failed"); - httpd_resp_send_500(req); - return ESP_FAIL; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN); + if (size > 1) { + i2c_master_read(cmd, data_rd, size - 1, ACK_VAL); } - - res = httpd_resp_set_type(req, "image/x-windows-bmp") - || httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp") - || httpd_resp_send(req, (const char *)buf, buf_len); - free(buf); - int64_t fr_end = esp_timer_get_time(); - ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000)); - return res; + i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + return ret; } ``` - - - diff --git a/conversions/to_jpg.cpp b/conversions/to_jpg.cpp index 24cc298..815979e 100644 --- a/conversions/to_jpg.cpp +++ b/conversions/to_jpg.cpp @@ -209,7 +209,7 @@ bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf { //todo: allocate proper buffer for holding JPEG data //this should be enough for CIF frame size - int jpg_buf_len = 128*1024; + int jpg_buf_len = 1024*1024; // 2M uint8_t * jpg_buf = (uint8_t *)_malloc(jpg_buf_len); diff --git a/driver/cam_hal.c b/driver/cam_hal.c index f5ca22e..2b258e8 100644 --- a/driver/cam_hal.c +++ b/driver/cam_hal.c @@ -14,7 +14,6 @@ #include #include -#include #include "esp_heap_caps.h" #include "ll_cam.h" #include "cam_hal.h" @@ -266,7 +265,7 @@ static esp_err_t cam_dma_config(const camera_config_t *config) cam_obj->dma_buffer = NULL; cam_obj->dma = NULL; - cam_obj->frames = (cam_frame_t *)heap_caps_aligned_calloc(alignof(cam_frame_t), 1, cam_obj->frame_cnt * sizeof(cam_frame_t), MALLOC_CAP_DEFAULT); + cam_obj->frames = (cam_frame_t *)heap_caps_calloc(1, cam_obj->frame_cnt * sizeof(cam_frame_t), MALLOC_CAP_DEFAULT); CAM_CHECK(cam_obj->frames != NULL, "frames malloc failed", ESP_FAIL); uint8_t dma_align = 0; @@ -374,11 +373,7 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint cam_obj->height = resolution[frame_size].height; if(cam_obj->jpeg_mode){ -#ifdef CONFIG_CAMERA_JPEG_MODE_FRAME_SIZE_AUTO - cam_obj->recv_size = cam_obj->width * cam_obj->height / 5; -#else - cam_obj->recv_size = CONFIG_CAMERA_JPEG_MODE_FRAME_SIZE; -#endif + cam_obj->recv_size = 2592*1944; cam_obj->fb_size = cam_obj->recv_size; } else { cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel; @@ -440,7 +435,7 @@ esp_err_t cam_deinit(void) } ll_cam_deinit(cam_obj); - + if (cam_obj->dma) { free(cam_obj->dma); } @@ -478,16 +473,6 @@ camera_fb_t *cam_take(TickType_t timeout) camera_fb_t *dma_buffer = NULL; TickType_t start = xTaskGetTickCount(); xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout); -#if CONFIG_IDF_TARGET_ESP32S3 - // Currently (22.01.2024) there is a bug in ESP-IDF v5.2, that causes - // GDMA to fall into a strange state if it is running while WiFi STA is connecting. - // This code tries to reset GDMA if frame is not received, to try and help with - // this case. It is possible to have some side effects too, though none come to mind - if (!dma_buffer) { - ll_cam_dma_reset(cam_obj); - xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout); - } -#endif if (dma_buffer) { if(cam_obj->jpeg_mode){ // find the end marker for JPEG. Data after that can be discarded @@ -499,11 +484,7 @@ camera_fb_t *cam_take(TickType_t timeout) } else { ESP_LOGW(TAG, "NO-EOI"); cam_give(dma_buffer); - TickType_t ticks_spent = xTaskGetTickCount() - start; - if (ticks_spent >= timeout) { - return NULL; /* We are out of time */ - } - return cam_take(timeout - ticks_spent);//recurse!!!! + return cam_take(timeout - (xTaskGetTickCount() - start));//recurse!!!! } } else if(cam_obj->psram_mode && cam_obj->in_bytes_per_pixel != cam_obj->fb_bytes_per_pixel){ //currently this is used only for YUV to GRAYSCALE @@ -512,13 +493,9 @@ camera_fb_t *cam_take(TickType_t timeout) return dma_buffer; } else { ESP_LOGW(TAG, "Failed to get the frame on time!"); -// #if CONFIG_IDF_TARGET_ESP32S3 -// ll_cam_dma_print_state(cam_obj); -// #endif } return NULL; } - void cam_give(camera_fb_t *dma_buffer) { for (int x = 0; x < cam_obj->frame_cnt; x++) { diff --git a/driver/esp_camera.c b/driver/esp_camera.c index 7c693a6..c5ce87c 100644 --- a/driver/esp_camera.c +++ b/driver/esp_camera.c @@ -98,6 +98,9 @@ static camera_state_t *s_state = NULL; #define CAMERA_DISABLE_OUT_CLOCK() camera_disable_out_clock() #endif +#define analog_gain 6 +#define mamual_exp_h 6 +#define mamual_exp_l 6 typedef struct { int (*detect)(int slv_addr, sensor_id_t *id); int (*init)(sensor_t *sensor); @@ -159,7 +162,7 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out return ESP_ERR_INVALID_STATE; } - s_state = (camera_state_t *) calloc(1, sizeof(camera_state_t)); + s_state = (camera_state_t *) calloc(sizeof(camera_state_t), 1); if (!s_state) { return ESP_ERR_NO_MEM; } @@ -190,10 +193,14 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out gpio_config(&conf); // carefull, logic is inverted compared to reset pin - gpio_set_level(config->pin_pwdn, 1); - vTaskDelay(10 / portTICK_PERIOD_MS); - gpio_set_level(config->pin_pwdn, 0); + gpio_set_level(config->pin_pwdn,1); vTaskDelay(10 / portTICK_PERIOD_MS); + + // close the led + conf.pin_bit_mask = 1LL << 3; + conf.mode = GPIO_MODE_OUTPUT; + gpio_config(&conf); + gpio_set_level(3, 0); } if (config->pin_reset >= 0) { @@ -201,12 +208,13 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out gpio_config_t conf = { 0 }; conf.pin_bit_mask = 1LL << config->pin_reset; conf.mode = GPIO_MODE_OUTPUT; - gpio_config(&conf); + gpio_config(&conf); gpio_set_level(config->pin_reset, 0); vTaskDelay(10 / portTICK_PERIOD_MS); gpio_set_level(config->pin_reset, 1); vTaskDelay(10 / portTICK_PERIOD_MS); + } ESP_LOGD(TAG, "Searching for camera address"); @@ -293,7 +301,14 @@ esp_err_t esp_camera_init(const camera_config_t *config) framesize_t frame_size = (framesize_t) config->frame_size; pixformat_t pix_format = (pixformat_t) config->pixel_format; - + BRIGHTNESS_t brightness_t0 = (BRIGHTNESS_t) config->brightness_t; + CONTRAST_t contrast_t0 = (CONTRAST_t) config->contrast_t; + SATURATION_t saturation_t0 = (SATURATION_t) config->saturation_t; + EXPOSURE_t exposure_t0 = (EXPOSURE_t) config->exposure_t; + SPECIAL special0 = (SPECIAL) config->special; + AWB_MODE awb_mode0 = (AWB_MODE) config->awb_mode; + IMAGE_QUALITY image_quality0 = (IMAGE_QUALITY) config->image_quality; + AGC_MODE agc_mode0 = (AGC_MODE) config->agc_mode; if (PIXFORMAT_JPEG == pix_format && (!camera_sensor[camera_model].support_jpeg)) { ESP_LOGE(TAG, "JPEG format is not supported on this sensor"); err = ESP_ERR_NOT_SUPPORTED; @@ -304,43 +319,21 @@ esp_err_t esp_camera_init(const camera_config_t *config) ESP_LOGW(TAG, "The frame size exceeds the maximum for this sensor, it will be forced to the maximum possible value"); frame_size = camera_sensor[camera_model].max_size; } - err = cam_config(config, frame_size, s_state->sensor.id.PID); if (err != ESP_OK) { ESP_LOGE(TAG, "Camera config failed with error 0x%x", err); goto fail; } - s_state->sensor.status.framesize = frame_size; s_state->sensor.pixformat = pix_format; - - ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height); + s_state->sensor.status.framesize = frame_size; + s_state->sensor.set_pixformat(&s_state->sensor, pix_format); if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) { ESP_LOGE(TAG, "Failed to set frame size"); err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE; goto fail; - } - s_state->sensor.set_pixformat(&s_state->sensor, pix_format); -#if CONFIG_CAMERA_CONVERTER_ENABLED - if(config->conv_mode) { - s_state->sensor.pixformat = get_output_data_format(config->conv_mode); // If conversion enabled, change the out data format by conversion mode - } -#endif - - if (s_state->sensor.id.PID == OV2640_PID) { - s_state->sensor.set_gainceiling(&s_state->sensor, GAINCEILING_2X); - s_state->sensor.set_bpc(&s_state->sensor, false); - s_state->sensor.set_wpc(&s_state->sensor, true); - s_state->sensor.set_lenc(&s_state->sensor, true); - } - - if (pix_format == PIXFORMAT_JPEG) { - s_state->sensor.set_quality(&s_state->sensor, config->jpeg_quality); - } - s_state->sensor.init_status(&s_state->sensor); - + } cam_start(); - return ESP_OK; fail: diff --git a/driver/include/esp_camera.h b/driver/include/esp_camera.h index ce031c8..3ce7023 100755 --- a/driver/include/esp_camera.h +++ b/driver/include/esp_camera.h @@ -67,6 +67,7 @@ #pragma once #include "esp_err.h" +#include "esp_log.h" #include "driver/ledc.h" #include "sensor.h" #include "sys/time.h" @@ -145,7 +146,14 @@ typedef struct { pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */ framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */ - + BRIGHTNESS_t brightness_t; + CONTRAST_t contrast_t; + SATURATION_t saturation_t; + EXPOSURE_t exposure_t; + AWB_MODE awb_mode; + SPECIAL special; + IMAGE_QUALITY image_quality; + AGC_MODE agc_mode; int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */ size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */ camera_fb_location_t fb_location; /*!< The location where the frame buffer will be allocated */ diff --git a/driver/include/sensor.h b/driver/include/sensor.h index f57e4e2..c2fadda 100755 --- a/driver/include/sensor.h +++ b/driver/include/sensor.h @@ -31,7 +31,7 @@ typedef enum { SC101IOT_PID = 0xda4a, SC030IOT_PID = 0x9a46, SC031GS_PID = 0x0031, - MEGA_CCM_PID =0x039E, + MEGA_CCM_PID = 0x039E, } camera_pid_t; typedef enum { @@ -68,8 +68,8 @@ typedef enum { BF20A6_SCCB_ADDR = 0x6E, SC101IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1 SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1 - SC031GS_SCCB_ADDR = 0x30, - MEGA_CCM_SCCB_ADDR = 0x1F, // 0x3E >> 1 + SC031GS_SCCB_ADDR = 0x30, + MEGA_CCM_SCCB_ADDR = 0x1F,// 0x3E >> 1 } camera_sccb_addr_t; typedef enum { @@ -84,15 +84,103 @@ typedef enum { PIXFORMAT_RGB555, // 3BP2P/RGB555 } pixformat_t; +typedef enum { + RST_PIN_LOW, // 0 + RST_PIN_HIGHT, // 1 +} camera_test_t; + +typedef enum { + brightness_0, // default + brightness_1, // +1 + brightness_2, // -1 + brightness_3, // +2 + brightness_4, // -2 + brightness_5, // +3 + brightness_6, // -3 + brightness_7, // +4 + brightness_8, // -4 +} BRIGHTNESS_t; + +typedef enum { + contrast_0 , // default + contrast_1, // +1 + contrast_2, // -1 + contrast_3, // +2 + contrast_4, // -2 + contrast_5, // +3 + contrast_6, // -3 +} CONTRAST_t; + +typedef enum { + saturation_0 , // default + saturation_1, // +1 + saturation_2, // -1 + saturation_3, // +2 + saturation_4, // -2 + saturation_5, // +3 + saturation_6, // -3 +} SATURATION_t; + + +typedef enum { + exposure_0 , // default + exposure_1, // +1 + exposure_2, // -1 + exposure_3, // +2 + exposure_4, // -2 + exposure_5, // +3 + exposure_6, // -3 +} EXPOSURE_t; +typedef enum { + Auto, + sunny, + office, + cloudy, + home, +} AWB_MODE; + +typedef enum { + normal, + blueish, + redish, + BorW, + sepia, + negative, + greenish, +} SPECIAL; + +typedef enum { + quality_high, + quality_default, + quality_low, +} IMAGE_QUALITY; + +typedef enum { + mirror_disable, + mirror_enable, +} IMAGE_MIRROR; + + +typedef enum { + flip_disable, + flip_enable, +} IMAGE_FLIP; + +typedef enum { + AGC_Auto, + AGC_Manual, +} AGC_MODE; + + typedef enum { FRAMESIZE_96X96, // 96x96 + FRAMESIZE_128x128, // 128x128 FRAMESIZE_QQVGA, // 160x120 - FRAMESIZE_128X128, // 128x128 FRAMESIZE_QCIF, // 176x144 FRAMESIZE_HQVGA, // 240x176 FRAMESIZE_240X240, // 240x240 FRAMESIZE_QVGA, // 320x240 - FRAMESIZE_320X320, // 320x320 + FRAMESIZE_320x320, // 320x320 FRAMESIZE_CIF, // 400x296 FRAMESIZE_HVGA, // 480x320 FRAMESIZE_VGA, // 640x480 @@ -103,8 +191,8 @@ typedef enum { FRAMESIZE_UXGA, // 1600x1200 // 3MP Sensors FRAMESIZE_FHD, // 1920x1080 - FRAMESIZE_P_HD, // 720x1280 - FRAMESIZE_P_3MP, // 864x1536 + FRAMESIZE_P_HD, // 720x1280 + FRAMESIZE_P_3MP, // 864x1536 FRAMESIZE_QXGA, // 2048x1536 // 5MP Sensors FRAMESIZE_QHD, // 2560x1440 @@ -189,11 +277,12 @@ typedef struct { uint8_t denoise; uint8_t special_effect;//0 - 6 uint8_t wb_mode;//0 - 4 + uint8_t AGC_mode;//0 - 4 uint8_t awb; uint8_t awb_gain; uint8_t aec; uint8_t aec2; - int8_t ae_level;//-2 - 2 + int8_t ae_level;//-2 - 2 uint16_t aec_value;//0 - 1200 uint8_t agc; uint8_t agc_gain;//0 - 30 @@ -216,41 +305,41 @@ typedef struct _sensor { camera_status_t status; int xclk_freq_hz; - // Sensor function pointers - int (*init_status) (sensor_t *sensor); - int (*reset) (sensor_t *sensor); // Reset the configuration of the sensor, and return ESP_OK if reset is successful + // Sensor function pointers + int (*set_Camera_rest) (sensor_t *sensor, int level); int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat); int (*set_framesize) (sensor_t *sensor, framesize_t framesize); + int (*set_brightness) (sensor_t *sensor, int level); 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_exposure_ctrl) (sensor_t *sensor, int enable); + int (*set_wb_mode) (sensor_t *sensor, int mode); + int (*set_special_effect) (sensor_t *sensor, int effect); + int (*set_quality) (sensor_t *sensor, int quality); + int (*set_AGC_mode) (sensor_t *sensor, int mode); + int (*set_agc_gain) (sensor_t *sensor, int gain); + int (*set_mamual_exp_h) (sensor_t *sensor, int level); + int (*set_mamual_exp_l) (sensor_t *sensor, int level); + + int (*init_status) (sensor_t *sensor); + int (*reset) (sensor_t *sensor); // Reset the configuration of the sensor, and return ESP_OK if reset is successful 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); int (*set_whitebal) (sensor_t *sensor, int enable); int (*set_gain_ctrl) (sensor_t *sensor, int enable); - int (*set_exposure_ctrl) (sensor_t *sensor, int enable); int (*set_hmirror) (sensor_t *sensor, int enable); int (*set_vflip) (sensor_t *sensor, int enable); - int (*set_aec2) (sensor_t *sensor, int enable); int (*set_awb_gain) (sensor_t *sensor, int enable); - int (*set_agc_gain) (sensor_t *sensor, int gain); int (*set_aec_value) (sensor_t *sensor, int gain); - - int (*set_special_effect) (sensor_t *sensor, int effect); - int (*set_wb_mode) (sensor_t *sensor, int mode); int (*set_ae_level) (sensor_t *sensor, int level); - int (*set_dcw) (sensor_t *sensor, int enable); int (*set_bpc) (sensor_t *sensor, int enable); int (*set_wpc) (sensor_t *sensor, int enable); - 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); diff --git a/driver/sccb.c b/driver/sccb.c index 7007883..307166d 100755 --- a/driver/sccb.c +++ b/driver/sccb.c @@ -6,7 +6,6 @@ * SCCB (I2C like) driver. * */ - #include #include #include diff --git a/driver/sensor.c b/driver/sensor.c index e0acbfc..1785b99 100644 --- a/driver/sensor.c +++ b/driver/sensor.c @@ -22,7 +22,7 @@ const camera_sensor_info_t camera_sensor[CAMERA_MODEL_MAX] = { const resolution_info_t resolution[FRAMESIZE_INVALID] = { { 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */ - { 128, 128, ASPECT_RATIO_1X1 }, /* 128x128 */ + { 128, 128, ASPECT_RATIO_1X1 }, /* 128x128 */ { 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */ { 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */ { 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */ @@ -47,7 +47,7 @@ const resolution_info_t resolution[FRAMESIZE_INVALID] = { { 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */ { 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */ { 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */ - { 2592, 1944, ASPECT_RATIO_4X3 }, /* 5MP */ + { 2592, 1944, ASPECT_RATIO_4X3 }, /* QSXGA */ }; camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id) diff --git a/idf_component.yml b/idf_component.yml index d51d369..2b98f8d 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,5 +1,2 @@ description: ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors. url: https://github.com/espressif/esp32-camera -issues: https://github.com/espressif/esp32-camera/issues -documentation: https://github.com/espressif/esp32-camera/tree/main/README.md -repository: https://github.com/espressif/esp32-camera.git diff --git a/sensors/bf20a6.c b/sensors/bf20a6.c index f8eb127..b1179c3 100644 --- a/sensors/bf20a6.c +++ b/sensors/bf20a6.c @@ -161,12 +161,6 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) case PIXFORMAT_RAW: set_reg_bits(sensor, 0x12, 0, 1, 0x1); break; - case PIXFORMAT_GRAYSCALE: - write_reg(sensor->slv_addr, 0x12, 0x23); - write_reg(sensor->slv_addr, 0x3a, 0x00); - write_reg(sensor->slv_addr, 0xe1, 0x92); - write_reg(sensor->slv_addr, 0xe3, 0x02); - break; default: ESP_LOGW(TAG, "set_pix unsupport format"); ret = -1; diff --git a/sensors/gc0308.c b/sensors/gc0308.c index 09d3331..f19025e 100644 --- a/sensors/gc0308.c +++ b/sensors/gc0308.c @@ -160,10 +160,6 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) write_reg(sensor->slv_addr, 0xfe, 0x00); ret = set_reg_bits(sensor->slv_addr, 0x24, 0, 0x0f, 2); //yuv422 Y Cb Y Cr break; - case PIXFORMAT_GRAYSCALE: - write_reg(sensor->slv_addr, 0xfe, 0x00); - ret = write_reg(sensor->slv_addr, 0x24, 0xb1); - break; default: ESP_LOGW(TAG, "unsupport format"); ret = -1; @@ -257,8 +253,8 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) write_reg(sensor->slv_addr, 0xf7, col_s / 4); write_reg(sensor->slv_addr, 0xf8, row_s / 4); - write_reg(sensor->slv_addr, 0xf9, (col_s + w) / 4); - write_reg(sensor->slv_addr, 0xfa, (row_s + h) / 4); + write_reg(sensor->slv_addr, 0xf9, (col_s + h) / 4); + write_reg(sensor->slv_addr, 0xfa, (row_s + w) / 4); write_reg(sensor->slv_addr, 0x05, H8(row_s)); write_reg(sensor->slv_addr, 0x06, L8(row_s)); diff --git a/sensors/mega_ccm.c b/sensors/mega_ccm.c index 159c392..6bd89de 100644 --- a/sensors/mega_ccm.c +++ b/sensors/mega_ccm.c @@ -32,49 +32,115 @@ static const char *TAG = "mega_ccm"; #define H8(v) ((v)>>8) #define L8(v) ((v)&0xff) - +#define brightness_max 8 +#define contarst_max 6 +#define saturation_max 6 +#define exposure_max 6 +#define awb_mode_max 4 +#define special_max 6 +#define quality_max 2 +#define mirror_max 2 +#define flip_max 2 +#define agc_mode_max 1 +#define analog_gain_max 6 +#define mamual_exp_h_max 6 +#define mamual_exp_l_max 6 //#define REG_DEBUG_ON - -static int read_reg(uint8_t slv_addr, const uint16_t reg){ +static int read_reg(uint8_t slv_addr, const uint16_t reg) +{ int ret = SCCB_Read16(slv_addr, reg); -#ifdef REG_DEBUG_ON - if (ret < 0) { - ESP_LOGE(TAG, "READ REG 0x%04x FAILED: %d", reg, ret); - } -#endif return ret; } -static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value){ +static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value) +{ int ret = 0; - ret = SCCB_Write16(slv_addr, reg, value); + + ret = SCCB_Write16(slv_addr,reg, value); return ret; } +static void print_regs(uint8_t slv_addr) +{ +#ifdef DEBUG_PRINT_REG + vTaskDelay(pdMS_TO_TICKS(100)); + ESP_LOGI(TAG, "REG list look ======================"); + for (size_t i = 0xf0; i <= 0xfe; i++) { + ESP_LOGI(TAG, "reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i)); + } + ESP_LOGI(TAG, "\npage 0 ==="); + write_reg(slv_addr, 0xfe, 0x00); // page 0 + for (size_t i = 0x03; i <= 0x24; i++) { + ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i)); + } + for (size_t i = 0x40; i <= 0x95; i++) { + ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i)); + } + ESP_LOGI(TAG, "\npage 3 ==="); + write_reg(slv_addr, 0xfe, 0x03); // page 3 + for (size_t i = 0x01; i <= 0x43; i++) { + ESP_LOGI(TAG, "p3 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i)); + } +#endif +} + + static int reset(sensor_t *sensor) { - int ret; + int ret = 0; + // Reset mega-ccm: clear all registers and reset them to their default values ret = write_reg(sensor->slv_addr, CAMERA_RST_REG, 0x00); - ret += write_reg(sensor->slv_addr, CAMERA_RST_REG, 0x01); - vTaskDelay(1000 / portTICK_PERIOD_MS); + if (ret) { + ESP_LOGE(TAG, "Software Reset FAILED!"); + return ret; + } + vTaskDelay(100 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Software Reset slv_addr %x address: %x, data: %x",sensor->slv_addr,CAMERA_RST_REG,0x01); + + ret = write_reg(sensor->slv_addr, CAMERA_RST_REG, 0x01); + if (ret) { + ESP_LOGE(TAG, "Software Reset FAILED!"); + return ret; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); // add 1s delay to wait mega-ccm init normal + + + + return ret; } +// static int set_Camera_rest(sensor_t *sensor, int level) +// { +// int ret = 0; +// if (level > camera_rest_max) { +// ESP_LOGW(TAG, "Invalid Camera_rest: %u", level); +// level = camera_rest_max; +// } +// ret = write_reg(sensor->slv_addr, CAMERA_RST_REG, level); +// if (ret == 0) { +// ESP_LOGD(TAG, "Set Camera_rest to: %d", level); +// } +// return ret; +// } static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) { int ret = 0; switch (pixformat) { case PIXFORMAT_JPEG: - ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x01); + ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x01); //JPEG break; + case PIXFORMAT_RGB565: - ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x02); + ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x10); //RGB565 break; + case PIXFORMAT_YUV422: - ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x03); + ret = write_reg(sensor->slv_addr, PIXEL_FMT_REG, 0x11); //YUV422 break; + default: ESP_LOGW(TAG, "unsupport format"); ret = -1; @@ -87,10 +153,8 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) return ret; } - static int set_framesize(sensor_t *sensor, framesize_t framesize) { - ESP_LOGI(TAG, "set_framesize"); int ret = 0; if (framesize > FRAMESIZE_5MP) { ESP_LOGW(TAG, "Invalid framesize: %u", framesize); @@ -99,237 +163,439 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) sensor->status.framesize = framesize; uint16_t w = resolution[framesize].width; uint16_t h = resolution[framesize].height; - switch (framesize){ - case FRAMESIZE_QVGA: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x01); //320x240 - ret += write_reg(sensor->slv_addr, SYSTEM_CLK_DIV_REG, 0x02); // set system clk - ret += write_reg(sensor->slv_addr, SYSTEM_PLL_DIV_REG, 0x01); // set system pll - break; - case FRAMESIZE_VGA: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x02); //640x480 - ret += write_reg(sensor->slv_addr, SYSTEM_CLK_DIV_REG, 0x02); // set system clk - ret += write_reg(sensor->slv_addr, SYSTEM_PLL_DIV_REG, 0x01); // set system pll - break; - case FRAMESIZE_HD: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x03); //1280x720 - ret += write_reg(sensor->slv_addr, SYSTEM_CLK_DIV_REG, 0x02); // set system clk - ret += write_reg(sensor->slv_addr, SYSTEM_PLL_DIV_REG, 0x01); // set system pll - break; - case FRAMESIZE_UXGA: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x04); //1600x1200 - ret += write_reg(sensor->slv_addr, SYSTEM_CLK_DIV_REG, 0x02); // set system clk - ret += write_reg(sensor->slv_addr, SYSTEM_PLL_DIV_REG, 0x01); // set system pll - break; - case FRAMESIZE_FHD: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x05); //1920x1080 - ret += write_reg(sensor->slv_addr, SYSTEM_CLK_DIV_REG, 0x02); // set system clk - ret += write_reg(sensor->slv_addr, SYSTEM_PLL_DIV_REG, 0x01); // set system pll - break; - case FRAMESIZE_5MP: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x06); //2592x1944 - break; - case FRAMESIZE_96X96: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x07); //96x96 - break; - case FRAMESIZE_128X128: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x08); //128x128 - break; - case FRAMESIZE_320X320: - ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x09); //320x320 - break; - default: - ESP_LOGW(TAG, "unsupport framesize"); - ret = -1; - break; + + if(framesize == FRAMESIZE_QVGA){ //320x240 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x01); + }else if(framesize == FRAMESIZE_VGA){ //640x480 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x02); + }else if(framesize == FRAMESIZE_HD){ //1280x720 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x03); + }else if(framesize == FRAMESIZE_UXGA){ //1600x1200 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x04); + }else if(framesize == FRAMESIZE_FHD){ //1920x1080 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x05); + }else if(framesize == FRAMESIZE_5MP){ //2592x1944 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x06); + }else if (framesize == FRAMESIZE_96X96){ //96x96 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x07); + }else if(framesize == FRAMESIZE_128x128){ //128x128 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x08); + }else if(framesize == FRAMESIZE_320x320){ //320x320 + ret = write_reg(sensor->slv_addr, RESOLUTION_REG, 0x09); } if (ret == 0) { - ESP_LOGD(TAG, "Set framesize to: %ux%u", w, h); + ESP_LOGI(TAG, "Set framesize to: %ux%u", w, h); } + print_regs(sensor->slv_addr); return ret; } -static int set_hmirror(sensor_t *sensor, int enable) +static int set_brightness(sensor_t *sensor, int level) { int ret = 0; - sensor->status.hmirror = enable; - ret = write_reg(sensor->slv_addr, IMAGE_MIRROR_REG, enable); + if (level > brightness_max) { + ESP_LOGW(TAG, "Invalid brightness: %u", level); + level = brightness_max; + } + switch (level) { + case brightness_0: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x08); //-4 + break; + case brightness_1: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x06); //-3 + break; + case brightness_2: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x04); //-2 + break; + case brightness_3: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x02); //-1 + break; + case brightness_4: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x00); //default + break; + case brightness_5: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x01); //+1 + break; + case brightness_6: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x03); //+2 + break; + case brightness_7: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x05); //+3 + break; + case brightness_8: + ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, 0x07); //+4 + break; + default: + ESP_LOGW(TAG, "brightness fail"); + ret = -1; + break; + } if (ret == 0) { - ESP_LOGD(TAG, "Set h-mirror to: %d", enable); + ESP_LOGD(TAG, "Set brightness to: %d", level); } return ret; } -static int set_vflip(sensor_t *sensor, int enable) +static int set_contrast(sensor_t *sensor, int level) { int ret = 0; - sensor->status.vflip = enable; - ret = write_reg(sensor->slv_addr, IMAGE_FLIP_REG, enable); + if (level > contarst_max) { + ESP_LOGW(TAG, "Invalid contrast: %u", level); + level = contarst_max; + } + switch (level) { + case contrast_0: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x06); //-3 + break; + case contrast_1: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x04); //-2 + break; + case contrast_2: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x02); //-1 + break; + case contrast_3: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x00); //default + break; + case contrast_4: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x01); //+1 + break; + case contrast_5: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x03); //+2 + break; + case contrast_6: + ret = write_reg(sensor->slv_addr, CONTRAST_REG, 0x05); //+3 + break; + default: + ESP_LOGW(TAG, "contrast fail"); + ret = -1; + break; + } if (ret == 0) { - ESP_LOGD(TAG, "Set v-flip to: %d", enable); + ESP_LOGD(TAG, "Set contrast to: %d", level); } return ret; } -static int set_quality(sensor_t *sensor, int qs) + +static int set_saturation(sensor_t *sensor, int level) { int ret = 0; - ret = write_reg(sensor->slv_addr, IMAGE_QUALITY_REG, qs); + if (level > saturation_max) { + ESP_LOGW(TAG, "Invalid saturation: %u", level); + level = saturation_max; + } + switch (level) { + case saturation_0: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x06); //-3 + + break; + case saturation_1: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x04); //-2 + + break; + + case saturation_2: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x02); //-1 + break; + case saturation_3: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x00); //default + + break; + case saturation_4: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x01); //+1 + break; + case saturation_5: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x03); //+2 + + break; + case saturation_6: + ret = write_reg(sensor->slv_addr, SATURATION_REG, 0x05); //+3 + break; + default: + ESP_LOGW(TAG, "saturation fail"); + ret = -1; + break; + } if (ret == 0) { - sensor->status.quality = qs; - ESP_LOGD(TAG, "Set quality to: %d", qs); + ESP_LOGD(TAG, "Set saturation to: %d", level); } return ret; } - -static int set_brightness(sensor_t *sensor, int level) +static int set_exposure_ctrl(sensor_t *sensor, int enable) { int ret = 0; - if(level < 0) { - level = 0; - } else if(level > 8) { - level = 8; + if (enable > exposure_max) { + ESP_LOGW(TAG, "Invalid exposure: %u", enable); + enable = exposure_max; + } + switch (enable) { + case exposure_0: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x00); //default + break; + case exposure_1: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x01); //+1 + break; + case exposure_2: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x02); //-1 + break; + case exposure_3: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x03); //+2 + break; + case exposure_4: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x04); //-2 + break; + case exposure_5: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x05); //+3 + break; + case exposure_6: + ret = write_reg(sensor->slv_addr, EXP_COMPENSATE_REG, 0x06); //-3 + break; + default: + ESP_LOGW(TAG, "exposure fail"); + ret = -1; + break; } - ret = write_reg(sensor->slv_addr, BRIGHTNESS_REG, level); if (ret == 0) { - ESP_LOGD(TAG, "Set brightness to: %d", level); - sensor->status.brightness = level; + ESP_LOGD(TAG, "Set exposure to: %d", enable); } return ret; } - -static int set_contrast (sensor_t *sensor, int level) +static int set_wb_mode (sensor_t *sensor, int mode) { - int ret = 0; - if(level < 0) { - level = 0; - } else if(level > 6) { - level = 6; + int ret = 0; + if (mode > awb_mode_max) { + ESP_LOGW(TAG, "Invalid AWB_mode : %u", mode); + mode = awb_mode_max; + } + switch (mode) { + case Auto: + ret = write_reg(sensor->slv_addr, AWB_MODE_REG, 0x00); + break; + case sunny: + ret = write_reg(sensor->slv_addr, AWB_MODE_REG, 0x01); + break; + case office: + ret = write_reg(sensor->slv_addr, AWB_MODE_REG, 0x02); + break; + case cloudy: + ret = write_reg(sensor->slv_addr, AWB_MODE_REG, 0x03); + break; + case home: + ret = write_reg(sensor->slv_addr, AWB_MODE_REG, 0x04); + break; + default: + ESP_LOGW(TAG, "AWB_mode fail"); + ret = -1; + break; } - ret = write_reg(sensor->slv_addr, CONTRAST_REG, level); if (ret == 0) { - ESP_LOGD(TAG, "Set contrast to: %d", level); - sensor->status.contrast = level; + ESP_LOGD(TAG, "Set AWB_mode to: %d", mode); } return ret; } -static int set_saturation (sensor_t *sensor, int level) +static int set_special_effect (sensor_t *sensor, int effect) { - int ret = 0; - if(level < 0) { - level = 0; - } else if(level > 6) { - level = 6; + int ret = 0; + if (effect > special_max) { + ESP_LOGW(TAG, "Invalid special effect: %u", effect); + effect = special_max; + } + switch (effect) { + case normal: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x00); + break; + case blueish: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x01); + break; + case redish: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x02); + break; + case BorW: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x03); + break; + case sepia: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x04); + break; + case negative: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x05); + break; + case greenish: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x06); + break; + default: + ret = write_reg(sensor->slv_addr, SPECIAL_REG, 0x00); + break; } - ret = write_reg(sensor->slv_addr, SATURATION_REG, level); if (ret == 0) { - ESP_LOGD(TAG, "Set saturation to: %d", level); - sensor->status.saturation = level; + ESP_LOGD(TAG, "Set special effect to: %d", effect); } return ret; } -static int set_agc_mode (sensor_t *sensor, int enable) +static int set_quality (sensor_t *sensor, int quality) { int ret = 0; - ret = write_reg(sensor->slv_addr, AGC_MODE_REG, enable); - if (ret == 0) { - ESP_LOGD(TAG, "Set agc mode to: %d", enable); - sensor->status.aec = enable; + if (quality > quality_max) { + ESP_LOGW(TAG, "Invalid quality : %u", quality); + quality = quality_max; } + switch (quality) { + case quality_high: + ret = write_reg(sensor->slv_addr, IMAGE_QUALITY_REG, 0x00); + break; + case quality_default: + ret = write_reg(sensor->slv_addr, IMAGE_QUALITY_REG, 0x01); + break; + case quality_low: + ret = write_reg(sensor->slv_addr, IMAGE_QUALITY_REG, 0x02); + break; + } return ret; } -static int set_wb_mode (sensor_t *sensor, int mode) +static int set_mirror (sensor_t *sensor, int mirror) { - int ret = 0; - if(mode < 0) { - mode = 0; - } else if(mode > 5) { - mode = 5; + int ret = 0; + if (mirror > mirror_max) { + ESP_LOGW(TAG, "Invalid mirror : %u", mirror); + mirror = mirror_max; } - ret = write_reg(sensor->slv_addr, AWB_MODE_REG, mode); - if (ret == 0) { - ESP_LOGD(TAG, "Set wb_mode to: %d", mode); - sensor->status.wb_mode = mode; + switch (mirror) { + case mirror_enable: + ret = write_reg(sensor->slv_addr, IMAGE_MIRROR_REG, 0x01); + break; + case mirror_disable: + ret = write_reg(sensor->slv_addr, IMAGE_MIRROR_REG, 0x00); + break; + } + return ret; +} +static int set_flip (sensor_t *sensor, int flip) +{ + int ret = 0; + if (flip > flip_max) { + ESP_LOGW(TAG, "Invalid flip : %u", flip); + flip = mirror_max; } + switch (flip) { + case flip_enable: + ret = write_reg(sensor->slv_addr, IMAGE_FLIP_REG, 0x01); + break; + case flip_disable: + ret = write_reg(sensor->slv_addr, IMAGE_FLIP_REG, 0x00); + break; + } return ret; - } -static int set_special_effect (sensor_t *sensor, int effect) -{ - int ret = 0; - if(effect < 0) { - effect = 0; - } else if(effect > 6) { - effect = 6; +static int set_AGC_mode (sensor_t *sensor, int mode) +{ + int ret = 0; + if (mode > agc_mode_max) { + ESP_LOGW(TAG, "Invalid AGC_mode : %u", mode); + mode = agc_mode_max; + } + switch (mode) { + case AGC_Auto: + ret = write_reg(sensor->slv_addr, AGC_MODE_REG, 0x00); + break; + case AGC_Manual: + ret = write_reg(sensor->slv_addr, AGC_MODE_REG, 0x01); + break; + default: + ESP_LOGW(TAG, "AGC_mode fail"); + ret = -1; + break; } - ret = write_reg(sensor->slv_addr, SPECIAL_REG, effect); if (ret == 0) { - ESP_LOGD(TAG, "Set special_effect to: %d", effect); - sensor->status.special_effect = effect; + ESP_LOGD(TAG, "Set AGC_mode to: %d", mode); } return ret; - } - -static int analog_gain (sensor_t *sensor, int val) +static int set_agc_gain (sensor_t *sensor, int gain) { - - int ret = 0; - ret = write_reg(sensor->slv_addr, MANUAL_AGC_REG, val); + int ret = 0; + if (gain > analog_gain_max) { + ESP_LOGW(TAG, "Invalid analog_gain : %u", gain); + gain = analog_gain_max; + } + ret = write_reg(sensor->slv_addr, MANUAL_AGC_REG, gain); if (ret == 0) { - ESP_LOGD(TAG, "Set analog gain to: %d", val); + ESP_LOGD(TAG, "Set analog_gain to: %d", gain); } return ret; - } - -static int exposure_line (sensor_t *sensor, int val) +static int set_mamual_exp_h (sensor_t *sensor, int level) { + int ret = 0; + if (level > mamual_exp_h_max) { + ESP_LOGW(TAG, "Invalid mamual_exp_h : %u", level); + level = mamual_exp_h_max; + } + ret = write_reg(sensor->slv_addr, MANUAL_EXP_H_REG , level); + if (ret == 0) { + ESP_LOGD(TAG, "Set mamual_exp_h to: %d", level); + } + return ret; +} - int ret = 0; - ret = write_reg(sensor->slv_addr, MANUAL_EXP_H_REG, val>>8); - ret += write_reg(sensor->slv_addr, MANUAL_EXP_L_REG, val>>8); +static int set_mamual_exp_l (sensor_t *sensor, int level) +{ + int ret = 0; + if (level > mamual_exp_l_max) { + ESP_LOGW(TAG, "Invalid mamual_exp_l : %u", level); + level = mamual_exp_l_max; + } + ret = write_reg(sensor->slv_addr, MANUAL_EXP_L_REG , level); if (ret == 0) { - ESP_LOGD(TAG, "Set exposure_line to: %d", val); + ESP_LOGD(TAG, "Set mamual_exp_l to: %d", level); } return ret; +} + +static int get_reg(sensor_t *sensor, int reg, int mask) +{ + int ret = 0; + if (mask > 0xFF) { + ESP_LOGE(TAG, "mask should not more than 0xff"); + } else { + ret = read_reg(sensor->slv_addr, reg); + } + if (ret > 0) { + ret &= mask; + } + return ret; } +static int set_reg(sensor_t *sensor, int reg, int mask, int value) +{ + int ret = 0; + if (mask > 0xFF) { + ESP_LOGE(TAG, "mask should not more than 0xff"); + } else { + ret = read_reg(sensor->slv_addr, reg); + } + if (ret < 0) { + return ret; + } + value = (ret & ~mask) | (value & mask); + + if (mask > 0xFF) { + + } else { + ret = write_reg(sensor->slv_addr, reg, value); + } + return ret; +} static int init_status(sensor_t *sensor) { - sensor->status.brightness = 0; - sensor->status.contrast = 0; - sensor->status.saturation = 0; - sensor->status.sharpness = 0; - sensor->status.denoise = 0; - sensor->status.ae_level = 0; - sensor->status.gainceiling = 0; - sensor->status.awb = 0; - sensor->status.dcw = 0; - sensor->status.agc = 0; - sensor->status.aec = 0; - sensor->status.hmirror = 0; - sensor->status.vflip = 0; - sensor->status.colorbar = 0; - sensor->status.bpc = 0; - sensor->status.wpc = 0; - sensor->status.raw_gma = 0; - sensor->status.lenc = 0; - sensor->status.quality = 0; - sensor->status.special_effect = 0; - sensor->status.wb_mode = 0; - sensor->status.awb_gain = 0; - sensor->status.agc_gain = 0; - sensor->status.aec_value = 0; - sensor->status.aec2 = 0; + ESP_LOGW(TAG, "Unsupported"); return 0; } @@ -347,9 +613,9 @@ static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val) int mega_ccm_detect(int slv_addr, sensor_id_t *id) { if (MEGA_CCM_SCCB_ADDR == slv_addr) { - uint8_t h = read_reg(slv_addr, SENSOR_ID_HIGH); - uint8_t l = read_reg(slv_addr, SENSOR_ID_LOW); - uint16_t PID = (h<<8) | l; + uint8_t MIDH = SCCB_Read(slv_addr, UW_DEVICE_ID_HI); + uint8_t MIDL = SCCB_Read(slv_addr, UW_DEVICE_ID_LO); + uint16_t PID = MIDH << 8 | MIDL; if (MEGA_CCM_PID == PID) { id->PID = PID; return PID; @@ -366,42 +632,41 @@ int mega_ccm_init(sensor_t *sensor) sensor->reset = reset; sensor->set_pixformat = set_pixformat; sensor->set_framesize = set_framesize; - sensor->set_contrast = set_contrast; sensor->set_brightness = set_brightness; + sensor->set_contrast = set_contrast; sensor->set_saturation = set_saturation; + sensor->set_exposure_ctrl = set_exposure_ctrl; + sensor->set_wb_mode = set_wb_mode; + sensor->set_special_effect = set_special_effect; + sensor->set_quality = set_quality; + sensor->set_AGC_mode = set_AGC_mode; + sensor->set_agc_gain = set_agc_gain; + sensor->set_mamual_exp_h = set_mamual_exp_h; + sensor->set_mamual_exp_l= set_mamual_exp_l; + sensor->set_gainceiling = set_gainceiling_dummy; + sensor->set_sharpness = set_dummy; sensor->set_denoise = set_dummy; - sensor->set_gainceiling = set_gainceiling_dummy; - sensor->set_quality = set_quality; sensor->set_colorbar = set_dummy; sensor->set_whitebal = set_dummy; sensor->set_gain_ctrl = set_dummy; - sensor->set_exposure_ctrl = set_dummy; - sensor->set_hmirror = set_hmirror; - sensor->set_vflip = set_vflip; - - sensor->set_aec2 = set_agc_mode; + sensor->set_hmirror = set_mirror; + sensor->set_vflip = set_flip; + sensor->set_aec2 = set_dummy; sensor->set_awb_gain = set_dummy; - sensor->set_agc_gain = analog_gain; - sensor->set_aec_value = exposure_line; - - sensor->set_special_effect = set_special_effect; - sensor->set_wb_mode = set_wb_mode; + sensor->set_aec_value = set_dummy; sensor->set_ae_level = set_dummy; - sensor->set_dcw = set_dummy; sensor->set_bpc = set_dummy; sensor->set_wpc = set_dummy; - sensor->set_raw_gma = set_dummy; sensor->set_lenc = set_dummy; - - sensor->get_reg = NULL; - sensor->set_reg = NULL; + sensor->get_reg = get_reg; + sensor->set_reg = set_reg; sensor->set_res_raw = NULL; sensor->set_pll = NULL; sensor->set_xclk = NULL; - ESP_LOGD(TAG, "MEGA_CCM Attached"); + ESP_LOGD(TAG, "mega_ccm Attached"); return 0; } diff --git a/sensors/private_include/mega_ccm.h b/sensors/private_include/mega_ccm.h index bbad247..d210112 100644 --- a/sensors/private_include/mega_ccm.h +++ b/sensors/private_include/mega_ccm.h @@ -1,6 +1,6 @@ /* * - * MEGA_CCM driver. + * mega_ccm driver. * */ #ifndef __MEGA_CCM_H__ @@ -28,4 +28,4 @@ int mega_ccm_detect(int slv_addr, sensor_id_t *id); */ int mega_ccm_init(sensor_t *sensor); -#endif // __MEGA_CCM_H__ +#endif // __mega_ccm_H__ diff --git a/sensors/private_include/mega_ccm_regs.h b/sensors/private_include/mega_ccm_regs.h index dbd51dd..e0bc9b9 100644 --- a/sensors/private_include/mega_ccm_regs.h +++ b/sensors/private_include/mega_ccm_regs.h @@ -1,16 +1,19 @@ /* - * MEGA_CCM register definitions. + * GC032A register definitions. */ #ifndef __MEGA_CCM_REG_REGS_H__ #define __MEGA_CCM_REG_REGS_H__ - -#define ID_BASE 0x0000 -#define SENSOR_BASE 0x0100 -#define SYS_CLK_BASE 0x0200 -#define BYPASS_BASE 0XFFF0 - -#define SENSOR_ID_HIGH ID_BASE | 0x00 -#define SENSOR_ID_LOW ID_BASE | 0x01 + + + + +#endif //__MEGA_CCM_REG_REGS_H__ + +#define ID_BASE 0x0000 +#define SENSOR_BASE 0x0100 + +#define UW_DEVICE_ID_HI ID_BASE | 0x00 +#define UW_DEVICE_ID_LO ID_BASE | 0x01 #define FIRMWARE_VER ID_BASE | 0x02 #define CAMERA_RST_REG SENSOR_BASE|0x02 @@ -31,13 +34,14 @@ #define IMAGE_MIRROR_REG SENSOR_BASE|0x2C + #define AGC_MODE_REG SENSOR_BASE|0x30 #define MANUAL_AGC_REG SENSOR_BASE|0x31 +#define AE_MODE_REG SENSOR_BASE|0x32 #define MANUAL_EXP_H_REG SENSOR_BASE|0x33 #define MANUAL_EXP_L_REG SENSOR_BASE|0x34 +#define BYPASS 0xFFF0 - -#define SYSTEM_CLK_DIV_REG SYS_CLK_BASE|0x00 -#define SYSTEM_PLL_DIV_REG SYS_CLK_BASE|0x01 - -#endif //__MEGA_CCM_REG_REGS_H__ +#define CAM_RST_BIT ( 1 << 0 ) +#define CAM_PWDN_BIT ( 1 << 1 ) +#define CAM_PWEN_BIT ( 1 << 2 ) \ No newline at end of file diff --git a/sensors/private_include/mega_ccm_settings.h b/sensors/private_include/mega_ccm_settings.h index ff8e186..8df0234 100644 --- a/sensors/private_include/mega_ccm_settings.h +++ b/sensors/private_include/mega_ccm_settings.h @@ -1,5 +1,5 @@ -#ifndef _GC032A_SETTINGS_H_ -#define _GC032A_SETTINGS_H_ +#ifndef _MEGA_CCM_SETTINGS_H_ +#define _MEGA_CCM_SETTINGS_H_ #include #include @@ -10,9 +10,14 @@ #define REG_DLY 0xffff #define REGLIST_TAIL 0x0000 + +/* + * The default register settings, as obtained from OmniVision. There + * is really no making sense of most of these - lots of "reserved" values + * and such. + * + */ static const uint16_t mega_ccm_default_regs[][2] = { - {0x0120, 0x01 }, // JPEG - {0x0121, 0x01 }, // 320X240 {REGLIST_TAIL, 0x00}, }; diff --git a/sensors/private_include/sc031gs_settings.h b/sensors/private_include/sc031gs_settings.h index ba5ca02..255c1b2 100644 --- a/sensors/private_include/sc031gs_settings.h +++ b/sensors/private_include/sc031gs_settings.h @@ -78,13 +78,10 @@ struct sc031gs_regval { uint8_t val; }; -static const struct sc031gs_regval sc031gs_reset_regs[] = { - {0x0103, 0x01}, // soft reset. - {REG_DELAY, 10}, // delay. -}; - // 200*200, xclk=10M, fps=120fps -static const struct sc031gs_regval sc031gs_200x200_init_regs[] = { +static const struct sc031gs_regval sc031gs_default_init_regs[] = { + {0x0103, 0x01}, // soft reset. + {REG_DELAY, 10}, // delay. {0x0100, 0x00}, {0x36e9, 0x80}, {0x36f9, 0x80}, @@ -203,114 +200,3 @@ static const struct sc031gs_regval sc031gs_200x200_init_regs[] = { {0x3317, 0x0e}, {REG_NULL, 0x00}, }; - -// 640*480, xclk=20M, fps=50fps, xclk=10M, fps=25fps -static const struct sc031gs_regval sc031gs_640x480_50fps_init_regs[] = { - {0x0100, 0x00}, - {0x36e9, 0x80}, - {0x36f9, 0x80}, - {0x300f, 0x0f}, - {0x3018, 0x1f}, - {0x3019, 0xff}, - {0x301c, 0xb4}, - {0x301f, 0x6c}, - {0x3028, 0x82}, - {0x3200, 0x00}, - {0x3201, 0x00}, - {0x3202, 0x00}, - {0x3203, 0x08}, - {0x3204, 0x02}, - {0x3205, 0x8f}, - {0x3206, 0x01}, - {0x3207, 0xf7}, - {SC031GS_OUTPUT_WINDOW_WIDTH_H_REG, 0x02}, - {SC031GS_OUTPUT_WINDOW_WIDTH_L_REG, 0x80}, - {SC031GS_OUTPUT_WINDOW_HIGH_H_REG, 0x01}, - {SC031GS_OUTPUT_WINDOW_HIGH_L_REG, 0xe0}, - {0x320c, 0x03}, - {0x320d, 0x6e}, - {0x320e, 0x04}, - {0x320f, 0x72}, - {SC031GS_OUTPUT_WINDOW_START_Y_H_REG, 0x00}, - {SC031GS_OUTPUT_WINDOW_START_Y_L_REG, 0x08}, - {SC031GS_OUTPUT_WINDOW_START_X_H_REG, 0x00}, - {SC031GS_OUTPUT_WINDOW_START_X_L_REG, 0x08}, - {0x3220, 0x10}, - {0x3223, 0x50}, - {0x3250, 0xf0}, - {0x3251, 0x02}, - {0x3252, 0x03}, - {0x3253, 0xb0}, - {0x3254, 0x02}, - {0x3255, 0x07}, - {0x3304, 0x48}, - {0x3306, 0x38}, - {0x3309, 0x68}, - {0x330b, 0xe0}, - {0x330c, 0x18}, - {0x330f, 0x20}, - {0x3310, 0x10}, - {0x3314, 0x6d}, - {0x3315, 0x38}, - {0x3316, 0x68}, - {0x3317, 0x0f}, - {0x3329, 0x5c}, - {0x332d, 0x5c}, - {0x332f, 0x60}, - {0x3335, 0x64}, - {0x3344, 0x64}, - {0x335b, 0x80}, - {0x335f, 0x80}, - {0x3366, 0x06}, - {0x3385, 0x31}, - {0x3387, 0x51}, - {0x3389, 0x01}, - {0x33b1, 0x03}, - {0x33b2, 0x06}, - {0x3621, 0xa4}, - {0x3622, 0x05}, - {0x3624, 0x47}, - {0x3631, 0x48}, - {0x3633, 0x52}, - {0x3635, 0x18}, - {0x3636, 0x25}, - {0x3637, 0x89}, - {0x3638, 0x0f}, - {0x3639, 0x08}, - {0x363a, 0x00}, - {0x363b, 0x48}, - {0x363c, 0x06}, - {0x363e, 0xf8}, - {0x3640, 0x00}, - {0x3641, 0x01}, - {0x36ea, 0x36}, - {0x36eb, 0x1a}, - {0x36ec, 0x0a}, - {0x36ed, 0x23}, - {0x36fa, 0x36}, - {0x36fb, 0x10}, - {0x36fc, 0x01}, - {0x36fd, 0x03}, - {0x3908, 0x91}, - {0x3d08, 0x01}, - {0x3e01, 0x14}, - {0x3e02, 0x80}, - {0x3e06, 0x0c}, - {0x3f04, 0x03}, - {0x3f05, 0x4e}, - {0x4500, 0x59}, - {0x4501, 0xc4}, - {0x4809, 0x01}, - {0x4837, 0x1b}, - {0x5011, 0x00}, - {0x36e9, 0x20}, - {0x36f9, 0x24}, - {0x0100, 0x01}, // must write 0x0100 with 0x01, must delay no less then 7ms - //delay 10ms - {REG_DELAY, 0X0a}, - {0x4418, 0x08}, - {0x4419, 0x80}, - {0x363d, 0x10}, - {0x3630, 0x48}, - {REG_NULL, 0x00}, -}; \ No newline at end of file diff --git a/sensors/sc031gs.c b/sensors/sc031gs.c index 627b701..dbd75ea 100644 --- a/sensors/sc031gs.c +++ b/sensors/sc031gs.c @@ -204,7 +204,7 @@ static int set_aec_value(sensor_t *sensor, int value) static int reset(sensor_t *sensor) { - int ret = write_regs(sensor->slv_addr, sc031gs_reset_regs); + int ret = write_regs(sensor->slv_addr, sc031gs_default_init_regs); if (ret) { ESP_LOGE(TAG, "reset fail"); } @@ -217,11 +217,17 @@ static int set_output_window(sensor_t *sensor, int offset_x, int offset_y, int w { int ret = 0; //sc:H_start={0x3212[1:0],0x3213},H_length={0x3208[1:0],0x3209}, + // printf("%d, %d, %d, %d\r\n", ((offset_x>>8) & 0x03), offset_x & 0xff, ((w>>8) & 0x03), w & 0xff); + WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_START_X_H_REG, 0x0); // For now, we use x_start is 0x04 + WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_START_X_L_REG, 0x04); WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_WIDTH_H_REG, ((w>>8) & 0x03)); WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_WIDTH_L_REG, w & 0xff); //sc:V_start={0x3210[1:0],0x3211},V_length={0x320a[1:0],0x320b}, + // printf("%d, %d, %d, %d\r\n", ((offset_y>>8) & 0x03), offset_y & 0xff, ((h>>8) & 0x03), h & 0xff); + WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_START_Y_H_REG, 0x0); // For now, we use y_start is 0x08 + WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_START_Y_L_REG, 0x08); WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_HIGH_H_REG, ((h>>8) & 0x03)); WRITE_REG_OR_RETURN(SC031GS_OUTPUT_WINDOW_HIGH_L_REG, h & 0xff); @@ -234,21 +240,17 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) { uint16_t w = resolution[framesize].width; uint16_t h = resolution[framesize].height; + if(w > SC031GS_MAX_FRAME_WIDTH || h > SC031GS_MAX_FRAME_HIGH) { + goto err; + } - struct sc031gs_regval const *framesize_regs = sc031gs_200x200_init_regs; - if(framesize > FRAMESIZE_VGA) { + if(w != 200 || h != 200) { + ESP_LOGE(TAG, "Only support 200*200 for now, contact us if you want to use other resolutions"); goto err; - } else if(framesize > FRAMESIZE_QVGA) { - framesize_regs = sc031gs_640x480_50fps_init_regs; } uint16_t offset_x = (640-w) /2 + 4; uint16_t offset_y = (480-h) /2 + 4; - - int ret = write_regs(sensor->slv_addr, framesize_regs); - if (ret) { - ESP_LOGE(TAG, "reset fail"); - } if(set_output_window(sensor, offset_x, offset_y, w, h)) { goto err; diff --git a/target/esp32/ll_cam.c b/target/esp32/ll_cam.c index 73c9797..566ebb5 100644 --- a/target/esp32/ll_cam.c +++ b/target/esp32/ll_cam.c @@ -44,10 +44,6 @@ static inline int gpio_ll_get_level(gpio_dev_t *hw, int gpio_num) #define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c) #endif -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 2) -#define ets_delay_us esp_rom_delay_us -#endif - static const char *TAG = "esp32 ll_cam"; #define I2S_ISR_ENABLE(i) {I2S0.int_clr.i = 1;I2S0.int_ena.i = 1;} @@ -257,6 +253,7 @@ esp_err_t ll_cam_deinit(cam_obj_t *cam) esp_intr_free(cam->cam_intr_handle); cam->cam_intr_handle = NULL; } + gpio_uninstall_isr_service(); return ESP_OK; } @@ -490,7 +487,7 @@ size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid) { if (pix_format == PIXFORMAT_GRAYSCALE) { - if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID || sensor_pid == BF20A6_PID || sensor_pid == GC0308_PID) { + if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID) { if (xclk_freq_hz > 10000000) { sampling_mode = SM_0A00_0B00; dma_filter = ll_cam_dma_filter_yuyv_highspeed; diff --git a/target/esp32s2/ll_cam.c b/target/esp32s2/ll_cam.c index b021161..667a554 100644 --- a/target/esp32s2/ll_cam.c +++ b/target/esp32s2/ll_cam.c @@ -37,7 +37,7 @@ static const char *TAG = "s2 ll_cam"; #define I2S_ISR_ENABLE(i) {I2S0.int_clr.i = 1;I2S0.int_ena.i = 1;} #define I2S_ISR_DISABLE(i) {I2S0.int_ena.i = 0;I2S0.int_clr.i = 1;} -static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) +static void IRAM_ATTR ll_cam_vsync_isr(void *arg) { //DBG_PIN_SET(1); cam_obj_t *cam = (cam_obj_t *)arg; @@ -54,7 +54,7 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) //DBG_PIN_SET(0); } -static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg) +static void IRAM_ATTR ll_cam_dma_isr(void *arg) { cam_obj_t *cam = (cam_obj_t *)arg; BaseType_t HPTaskAwoken = pdFALSE; @@ -95,6 +95,7 @@ esp_err_t ll_cam_deinit(cam_obj_t *cam) esp_intr_free(cam->cam_intr_handle); cam->cam_intr_handle = NULL; } + gpio_uninstall_isr_service(); return ESP_OK; } @@ -177,6 +178,8 @@ esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config) I2S0.sample_rate_conf.rx_bck_div_num = 1; I2S0.sample_rate_conf.rx_bits_mod = 8; + I2S0.conf1.rx_pcm_bypass = 1; + I2S0.conf2.i_v_sync_filter_en = 1; I2S0.conf2.i_v_sync_filter_thres = 4; I2S0.conf2.cam_sync_fifo_reset = 1; @@ -214,7 +217,7 @@ esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config) io_conf.pull_up_en = 1; io_conf.pull_down_en = 0; gpio_config(&io_conf); - gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | CAMERA_ISR_IRAM_FLAG); + gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM); gpio_isr_handler_add(config->pin_vsync, ll_cam_vsync_isr, cam); gpio_intr_disable(config->pin_vsync); @@ -252,7 +255,7 @@ esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config) esp_err_t ll_cam_init_isr(cam_obj_t *cam) { - return esp_intr_alloc(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_LOWMED | CAMERA_ISR_IRAM_FLAG, ll_cam_dma_isr, cam, &cam->cam_intr_handle); + return esp_intr_alloc(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, ll_cam_dma_isr, cam, &cam->cam_intr_handle); } void ll_cam_do_vsync(cam_obj_t *cam) @@ -391,7 +394,7 @@ size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid) { if (pix_format == PIXFORMAT_GRAYSCALE) { - if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID || sensor_pid == BF20A6_PID || sensor_pid == GC0308_PID) { + if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID) { cam->in_bytes_per_pixel = 1; // camera sends Y8 } else { cam->in_bytes_per_pixel = 2; // camera sends YU/YV diff --git a/target/esp32s3/ll_cam.c b/target/esp32s3/ll_cam.c index 71caf14..f8b94a3 100644 --- a/target/esp32s3/ll_cam.c +++ b/target/esp32s3/ll_cam.c @@ -20,8 +20,6 @@ #include "soc/gdma_struct.h" #include "soc/gdma_periph.h" #include "soc/gdma_reg.h" -#include "hal/clk_gate_ll.h" -#include "esp_private/gdma.h" #include "ll_cam.h" #include "cam_hal.h" #include "esp_rom_gpio.h" @@ -35,61 +33,9 @@ #define ets_delay_us(a) esp_rom_delay_us(a) #endif -#if !defined(SOC_GDMA_PAIRS_PER_GROUP) && defined(SOC_GDMA_PAIRS_PER_GROUP_MAX) -#define SOC_GDMA_PAIRS_PER_GROUP SOC_GDMA_PAIRS_PER_GROUP_MAX -#endif - static const char *TAG = "s3 ll_cam"; -void ll_cam_dma_print_state(cam_obj_t *cam) -{ - esp_rom_printf("dma_infifo_status[%u] :\n", cam->dma_num); - esp_rom_printf(" infifo_full_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l1); - esp_rom_printf(" infifo_empty_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l1); - esp_rom_printf(" infifo_full_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l2); - esp_rom_printf(" infifo_empty_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l2); - esp_rom_printf(" infifo_full_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_full_l3); - esp_rom_printf(" infifo_empty_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_empty_l3); - esp_rom_printf(" infifo_cnt_l1 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l1); - esp_rom_printf(" infifo_cnt_l2 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l2); - esp_rom_printf(" infifo_cnt_l3 : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.infifo_cnt_l3); - esp_rom_printf(" in_remain_under_1b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_1b_l3); - esp_rom_printf(" in_remain_under_2b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_2b_l3); - esp_rom_printf(" in_remain_under_3b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_3b_l3); - esp_rom_printf(" in_remain_under_4b_l3: %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_remain_under_4b_l3); - esp_rom_printf(" in_buf_hungry : %lu\n", GDMA.channel[cam->dma_num].in.infifo_status.in_buf_hungry); - esp_rom_printf("dma_state[%u] :\n", cam->dma_num); - esp_rom_printf(" dscr_addr : 0x%lx\n", GDMA.channel[cam->dma_num].in.state.dscr_addr); - esp_rom_printf(" in_dscr_state : %lu\n", GDMA.channel[cam->dma_num].in.state.in_dscr_state); - esp_rom_printf(" in_state : %lu\n", GDMA.channel[cam->dma_num].in.state.in_state); -} - -void ll_cam_dma_reset(cam_obj_t *cam) -{ - - GDMA.channel[cam->dma_num].in.int_clr.val = ~0; - GDMA.channel[cam->dma_num].in.int_ena.val = 0; - - GDMA.channel[cam->dma_num].in.conf0.val = 0; - GDMA.channel[cam->dma_num].in.conf0.in_rst = 1; - GDMA.channel[cam->dma_num].in.conf0.in_rst = 0; - - //internal SRAM only - if (!cam->psram_mode) { - GDMA.channel[cam->dma_num].in.conf0.indscr_burst_en = 1; - GDMA.channel[cam->dma_num].in.conf0.in_data_burst_en = 1; - } - - GDMA.channel[cam->dma_num].in.conf1.in_check_owner = 0; - // GDMA.channel[cam->dma_num].in.conf1.in_ext_mem_bk_size = 2; - - GDMA.channel[cam->dma_num].in.peri_sel.sel = 5; - //GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15 - //GDMA.channel[cam->dma_num].in.sram_size.in_size = 6;//This register is used to configure the size of L2 Tx FIFO for Rx channel. 0:16 bytes, 1:24 bytes, 2:32 bytes, 3: 40 bytes, 4: 48 bytes, 5:56 bytes, 6: 64 bytes, 7: 72 bytes, 8: 80 bytes. - //GDMA.channel[cam->dma_num].in.wight.rx_weight = 7;//The weight of Rx channel 0-15 -} - -static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) +static void IRAM_ATTR ll_cam_vsync_isr(void *arg) { //DBG_PIN_SET(1); cam_obj_t *cam = (cam_obj_t *)arg; @@ -112,7 +58,7 @@ static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg) //DBG_PIN_SET(0); } -static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg) +static void IRAM_ATTR ll_cam_dma_isr(void *arg) { cam_obj_t *cam = (cam_obj_t *)arg; BaseType_t HPTaskAwoken = pdFALSE; @@ -143,6 +89,25 @@ bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam) return true; } +esp_err_t ll_cam_deinit(cam_obj_t *cam) +{ + if (cam->cam_intr_handle) { + esp_intr_free(cam->cam_intr_handle); + cam->cam_intr_handle = NULL; + } + + if (cam->dma_intr_handle) { + esp_intr_free(cam->dma_intr_handle); + cam->dma_intr_handle = NULL; + } + GDMA.channel[cam->dma_num].in.link.addr = 0x0; + + LCD_CAM.cam_ctrl1.cam_start = 0; + LCD_CAM.cam_ctrl1.cam_reset = 1; + LCD_CAM.cam_ctrl1.cam_reset = 0; + return ESP_OK; +} + bool ll_cam_start(cam_obj_t *cam, int frame_pos) { LCD_CAM.cam_ctrl1.cam_start = 0; @@ -174,77 +139,48 @@ bool ll_cam_start(cam_obj_t *cam, int frame_pos) return true; } -esp_err_t ll_cam_deinit(cam_obj_t *cam) +static esp_err_t ll_cam_dma_init(cam_obj_t *cam) { - if (cam->cam_intr_handle) { - esp_intr_free(cam->cam_intr_handle); - cam->cam_intr_handle = NULL; + for (int x = (SOC_GDMA_PAIRS_PER_GROUP - 1); x >= 0; x--) { + if (GDMA.channel[x].in.link.addr == 0x0) { + cam->dma_num = x; + ESP_LOGI(TAG, "DMA Channel=%d", cam->dma_num); + break; + } + if (x == 0) { + cam_deinit(); + ESP_LOGE(TAG, "Can't found available GDMA channel"); + return ESP_FAIL; + } } - if (cam->dma_intr_handle) { - esp_intr_free(cam->dma_intr_handle); - cam->dma_intr_handle = NULL; + if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN) == 0) { + REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); + REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); + REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); + REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); } - gdma_disconnect(cam->dma_channel_handle); - gdma_del_channel(cam->dma_channel_handle); - cam->dma_channel_handle = NULL; - // GDMA.channel[cam->dma_num].in.link.addr = 0x0; - LCD_CAM.cam_ctrl1.cam_start = 0; - LCD_CAM.cam_ctrl1.cam_reset = 1; - LCD_CAM.cam_ctrl1.cam_reset = 0; - return ESP_OK; -} + GDMA.channel[cam->dma_num].in.int_clr.val = ~0; + GDMA.channel[cam->dma_num].in.int_ena.val = 0; -static esp_err_t ll_cam_dma_init(cam_obj_t *cam) -{ - //alloc rx gdma channel - gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - }; -#if ((ESP_IDF_VERSION_MAJOR == 5 && ESP_IDF_VERSION_MINOR >= 4) || ESP_IDF_VERSION_MAJOR > 5) - esp_err_t ret = gdma_new_ahb_channel(&rx_alloc_config, &cam->dma_channel_handle); -#else - esp_err_t ret = gdma_new_channel(&rx_alloc_config, &cam->dma_channel_handle); -#endif - if (ret != ESP_OK) { - cam_deinit(); - ESP_LOGE(TAG, "Can't find available GDMA channel"); - return ESP_FAIL; - } - int chan_id = -1; - ret = gdma_get_channel_id(cam->dma_channel_handle, &chan_id); - if (ret != ESP_OK) { - cam_deinit(); - ESP_LOGE(TAG, "Can't get GDMA channel number"); - return ESP_FAIL; - } - cam->dma_num = chan_id; - ESP_LOGI(TAG, "DMA Channel=%d", cam->dma_num); - // for (int x = (SOC_GDMA_PAIRS_PER_GROUP - 1); x >= 0; x--) { - // if (GDMA.channel[x].in.link.addr == 0x0) { - // cam->dma_num = x; - // ESP_LOGI(TAG, "DMA Channel=%d", cam->dma_num); - // break; - // } - // if (x == 0) { - // cam_deinit(); - // ESP_LOGE(TAG, "Can't found available GDMA channel"); - // return ESP_FAIL; - // } - // } - - if (!periph_ll_periph_enabled(PERIPH_GDMA_MODULE)) { - periph_ll_disable_clk_set_rst(PERIPH_GDMA_MODULE); - periph_ll_enable_clk_clear_rst(PERIPH_GDMA_MODULE); + GDMA.channel[cam->dma_num].in.conf0.val = 0; + GDMA.channel[cam->dma_num].in.conf0.in_rst = 1; + GDMA.channel[cam->dma_num].in.conf0.in_rst = 0; + + //internal SRAM only + if (!cam->psram_mode) { + GDMA.channel[cam->dma_num].in.conf0.indscr_burst_en = 1; + GDMA.channel[cam->dma_num].in.conf0.in_data_burst_en = 1; } - // if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN) == 0) { - // REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); - // REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); - // REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); - // REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); - // } - ll_cam_dma_reset(cam); + + GDMA.channel[cam->dma_num].in.conf1.in_check_owner = 0; + // GDMA.channel[cam->dma_num].in.conf1.in_ext_mem_bk_size = 2; + + GDMA.channel[cam->dma_num].in.peri_sel.sel = 5; + //GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15 + //GDMA.channel[cam->dma_num].in.sram_size.in_size = 6;//This register is used to configure the size of L2 Tx FIFO for Rx channel. 0:16 bytes, 1:24 bytes, 2:32 bytes, 3: 40 bytes, 4: 48 bytes, 5:56 bytes, 6: 64 bytes, 7: 72 bytes, 8: 80 bytes. + //GDMA.channel[cam->dma_num].in.wight.rx_weight = 7;//The weight of Rx channel 0-15 return ESP_OK; } @@ -299,16 +235,12 @@ static esp_err_t ll_cam_converter_config(cam_obj_t *cam, const camera_config_t * esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config) { esp_err_t ret = ESP_OK; - if (!periph_ll_periph_enabled(PERIPH_LCD_CAM_MODULE)) { - periph_ll_disable_clk_set_rst(PERIPH_LCD_CAM_MODULE); - periph_ll_enable_clk_clear_rst(PERIPH_LCD_CAM_MODULE); + if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN) == 0) { + REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN); + REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN); + REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST); + REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST); } - // if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN) == 0) { - // REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN); - // REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN); - // REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST); - // REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_LCD_CAM_RST); - // } LCD_CAM.cam_ctrl.val = 0; @@ -372,6 +304,8 @@ esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config) gpio_set_pull_mode(config->pin_pclk, GPIO_FLOATING); gpio_matrix_in(config->pin_pclk, CAM_PCLK_IDX, false); + printf("???????? %d ??? %ld\n", config->pin_vsync, GPIO_PIN_MUX_REG[config->pin_vsync]); + vTaskDelay(pdMS_TO_TICKS(200)); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_vsync], PIN_FUNC_GPIO); gpio_set_direction(config->pin_vsync, GPIO_MODE_INPUT); gpio_set_pull_mode(config->pin_vsync, GPIO_FLOATING); @@ -405,7 +339,7 @@ esp_err_t ll_cam_init_isr(cam_obj_t *cam) { esp_err_t ret = ESP_OK; ret = esp_intr_alloc_intrstatus(gdma_periph_signals.groups[0].pairs[cam->dma_num].rx_irq_id, - ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | CAMERA_ISR_IRAM_FLAG, + ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM, (uint32_t)&GDMA.channel[cam->dma_num].in.int_st, GDMA_IN_SUC_EOF_CH0_INT_ST_M, ll_cam_dma_isr, cam, &cam->dma_intr_handle); if (ret != ESP_OK) { @@ -414,7 +348,7 @@ esp_err_t ll_cam_init_isr(cam_obj_t *cam) } ret = esp_intr_alloc_intrstatus(ETS_LCD_CAM_INTR_SOURCE, - ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | CAMERA_ISR_IRAM_FLAG, + ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM, (uint32_t)&LCD_CAM.lc_dma_int_st.val, LCD_CAM_CAM_VSYNC_INT_ST_M, ll_cam_vsync_isr, cam, &cam->cam_intr_handle); if (ret != ESP_OK) { @@ -557,7 +491,7 @@ size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid) { if (pix_format == PIXFORMAT_GRAYSCALE) { - if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID || sensor_pid == BF20A6_PID || sensor_pid == GC0308_PID) { + if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID) { cam->in_bytes_per_pixel = 1; // camera sends Y8 } else { cam->in_bytes_per_pixel = 2; // camera sends YU/YV diff --git a/target/private_include/ll_cam.h b/target/private_include/ll_cam.h index df6135f..34c8da3 100644 --- a/target/private_include/ll_cam.h +++ b/target/private_include/ll_cam.h @@ -38,17 +38,6 @@ #if __has_include("esp_private/periph_ctrl.h") # include "esp_private/periph_ctrl.h" #endif -#if __has_include("esp_private/gdma.h") -# include "esp_private/gdma.h" -#endif - -#if CONFIG_LCD_CAM_ISR_IRAM_SAFE -#define CAMERA_ISR_IRAM_FLAG ESP_INTR_FLAG_IRAM -#define CAMERA_ISR_IRAM_ATTR IRAM_ATTR -#else -#define CAMERA_ISR_IRAM_FLAG 0 -#define CAMERA_ISR_IRAM_ATTR -#endif #define CAMERA_DBG_PIN_ENABLE 0 #if CAMERA_DBG_PIN_ENABLE @@ -115,9 +104,6 @@ typedef struct { uint8_t dma_num;//ESP32-S3 intr_handle_t dma_intr_handle;//ESP32-S3 -#if SOC_GDMA_SUPPORTED - gdma_channel_handle_t dma_channel_handle;//ESP32-S3 -#endif uint8_t jpeg_mode; uint8_t vsync_pin; @@ -156,10 +142,6 @@ uint8_t ll_cam_get_dma_align(cam_obj_t *cam); bool ll_cam_dma_sizes(cam_obj_t *cam); size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len); esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid); -#if CONFIG_IDF_TARGET_ESP32S3 -void ll_cam_dma_print_state(cam_obj_t *cam); -void ll_cam_dma_reset(cam_obj_t *cam); -#endif // implemented in cam_hal void ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken); diff --git a/target/xclk.c b/target/xclk.c index 7ee155b..384fed6 100755 --- a/target/xclk.c +++ b/target/xclk.c @@ -23,10 +23,6 @@ esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz) timer_conf.freq_hz = xclk_freq_hz; timer_conf.speed_mode = LEDC_LOW_SPEED_MODE; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) - timer_conf.deconfigure = false; -#endif - #if ESP_IDF_VERSION_MAJOR >= 4 timer_conf.clk_cfg = LEDC_AUTO_CLK; #endif @@ -47,7 +43,7 @@ esp_err_t camera_enable_out_clock(const camera_config_t* config) } g_ledc_channel = config->ledc_channel; - ledc_channel_config_t ch_conf = {0}; + ledc_channel_config_t ch_conf; ch_conf.gpio_num = config->pin_xclk; ch_conf.speed_mode = LEDC_LOW_SPEED_MODE; ch_conf.channel = config->ledc_channel;