Integration of OV5640 camera into an ESP32-S3 using GDMA and the LCD_CAM peripheral
Posted: Sat May 06, 2023 9:35 am
I am trying to integrate an OV5640 camera into an ESP32-S3 using GDMA and the LCD_CAM peripheral.
This is the first attempt and the objective is to verify that the peripheral captures the data from the camera interface and using GDMA writes it to the list buffer.
To check that everything works the DMA callback should be executed when the buffer is full and the content of desc.dw0.length should be 1470.
Neither of these two things happens, DMA callback is not executed and the desc.dw0.length content is 0.
Any help ?.
This is the first attempt and the objective is to verify that the peripheral captures the data from the camera interface and using GDMA writes it to the list buffer.
To check that everything works the DMA callback should be executed when the buffer is full and the content of desc.dw0.length should be 1470.
Neither of these two things happens, DMA callback is not executed and the desc.dw0.length content is 0.
Any help ?.
Code: Select all
// "ESP32S3 Dev Module" 2.0.8
#include <esp_rom_gpio.h>
#include <driver/periph_ctrl.h>
#include <esp_private/gdma.h>
#include <hal/dma_types.h>
#include <soc/lcd_cam_struct.h>
#define dmabuf_camrx_len 1470 // DMA camera RX buffer size
gdma_channel_handle_t dma_camrx_chan; // CAM RX DMA channel
uint8_t dmabuf_camrx[dmabuf_camrx_len]; // DMA RX camera buffer
dma_descriptor_t desc; // DMA RX camera descriptor
// End of DMA transfer callback
static IRAM_ATTR bool dma_callback(gdma_channel_handle_t dma_camrx_chan, gdma_event_data_t *event_data, void *user_data) {
Serial.println("End of DMA transfer");
return true;
}
#define pclk_pin 13
#define xclk_pin 21
#define href_pin 46
#define d2_pin 40
#define d3_pin 39
#define d4_pin 38
#define d5_pin 37
#define d6_pin 36
#define d7_pin 5
#define d8_pin 45
#define d9_pin 47
void setup() {
Serial.begin(115200);
// LCD_CAM peripheral enable and reset
periph_module_enable(PERIPH_LCD_CAM_MODULE);
periph_module_reset(PERIPH_LCD_CAM_MODULE);
////////// Reset CAM bus
LCD_CAM.cam_ctrl1.cam_reset = 1;
////////// CAM module registers configuration
LCD_CAM.cam_ctrl.cam_clk_sel = 1; // XTAL_CLK source (40MHz)
LCD_CAM.cam_ctrl.cam_clkm_div_num = 2; // CAM_CLK_IDX = 20MHz
LCD_CAM.cam_ctrl.cam_clkm_div_b = 0;
LCD_CAM.cam_ctrl.cam_clkm_div_a = 0;
LCD_CAM.cam_ctrl1.cam_vh_de_mode_en = 1;
LCD_CAM.cam_ctrl.cam_update = 1;
////////// Route CAM signals to GPIO pins
const struct {
uint32_t pin;
uint8_t signal;
} mux[] = {
{ d2_pin, CAM_DATA_IN0_IDX }, { d3_pin, CAM_DATA_IN1_IDX }, { d4_pin, CAM_DATA_IN2_IDX },
{ d5_pin, CAM_DATA_IN3_IDX }, { d6_pin, CAM_DATA_IN4_IDX }, { d7_pin, CAM_DATA_IN5_IDX },
{ d8_pin, CAM_DATA_IN6_IDX }, { d9_pin, CAM_DATA_IN7_IDX }, { pclk_pin, CAM_PCLK_IDX },
{ href_pin, CAM_H_ENABLE_IDX },
{ GPIO_MATRIX_CONST_ONE_INPUT, CAM_H_SYNC_IDX }, { GPIO_MATRIX_CONST_ONE_INPUT, CAM_V_SYNC_IDX }
};
for (int i = 0; i < 12; i++) {
if (mux[i].pin != GPIO_MATRIX_CONST_ONE_INPUT) {
esp_rom_gpio_pad_select_gpio(mux[i].pin);
}
esp_rom_gpio_connect_in_signal(mux[i].pin, mux[i].signal, false);
}
esp_rom_gpio_pad_select_gpio(xclk_pin);
esp_rom_gpio_pad_set_drv(xclk_pin, 3);
esp_rom_gpio_connect_out_signal(xclk_pin, CAM_CLK_IDX, false, false);
// GDMA descriptor
desc.dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
desc.dw0.suc_eof = 1; // Last descriptor
desc.dw0.size = dmabuf_camrx_len;
desc.buffer = dmabuf_camrx;
desc.next = NULL;
// Allocate DMA channel and connect it to the CAM peripheral
gdma_channel_alloc_config_t dma_camrx_chan_config = {
.sibling_chan = NULL,
.direction = GDMA_CHANNEL_DIRECTION_RX,
.flags = {
.reserve_sibling = 0
}
};
gdma_new_channel(&dma_camrx_chan_config, &dma_camrx_chan);
gdma_connect(dma_camrx_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0));
gdma_strategy_config_t strategy_config = {
.owner_check = false,
.auto_update_desc = false
};
gdma_apply_strategy(dma_camrx_chan, &strategy_config);
// Enable DMA transfer callback
gdma_rx_event_callbacks_t rx_cbs = {
.on_recv_eof = dma_callback
};
gdma_register_rx_event_callbacks(dma_camrx_chan, &rx_cbs, NULL);
// Here OV5640 camera configuration code using I2C
//////////////////////
// Camera interface is ok checked with a logic analyzer (xclk, pclk, vsync and href)
gdma_reset(dma_camrx_chan); // Reset DMA to known state
LCD_CAM.cam_ctrl.cam_update = 1; // Update registers
LCD_CAM.cam_ctrl1.cam_reset = 1;
LCD_CAM.cam_ctrl1.cam_reset = 0;
LCD_CAM.cam_ctrl1.cam_afifo_reset = 1;
LCD_CAM.cam_ctrl1.cam_afifo_reset = 0;
gdma_start(dma_camrx_chan, (intptr_t)&desc); // Start DMA
LCD_CAM.cam_ctrl1.cam_start = 1; // Trigger CAM DMA transfer
delay(10);
Serial.println(desc.dw0.length);
}
void loop() {
delay(100);
}