Page 1 of 1

Integration of OV5640 camera into an ESP32-S3 using GDMA and the LCD_CAM peripheral

Posted: Sat May 06, 2023 9:35 am
by JPMJPM
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 ?.

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); 
}
camera_interfgace.jpg
Camera interface
camera_interfgace.jpg (194.11 KiB) Viewed 1689 times