Skip to content

Commit

Permalink
Implement proper GDMA allocator and ISR from IRAM option (#629)
Browse files Browse the repository at this point in the history
* Implement proper GDMA allocator

* Add Kconfig option to execute ISR from IRAM on S2 and S3

Up until now, default was to execute from IRAM. This changes that for S2 and S3. ESP32 is left unchanged, because of the work that is required on it.
  • Loading branch information
me-no-dev authored Jan 29, 2024
1 parent 984999f commit f0bb429
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 49 deletions.
7 changes: 7 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,11 @@ 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
8 changes: 4 additions & 4 deletions target/esp32s2/ll_cam.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 IRAM_ATTR ll_cam_vsync_isr(void *arg)
static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg)
{
//DBG_PIN_SET(1);
cam_obj_t *cam = (cam_obj_t *)arg;
Expand All @@ -54,7 +54,7 @@ static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
//DBG_PIN_SET(0);
}

static void IRAM_ATTR ll_cam_dma_isr(void *arg)
static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg)
{
cam_obj_t *cam = (cam_obj_t *)arg;
BaseType_t HPTaskAwoken = pdFALSE;
Expand Down Expand Up @@ -217,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 | ESP_INTR_FLAG_IRAM);
gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | CAMERA_ISR_IRAM_FLAG);
gpio_isr_handler_add(config->pin_vsync, ll_cam_vsync_isr, cam);
gpio_intr_disable(config->pin_vsync);

Expand Down Expand Up @@ -255,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 | ESP_INTR_FLAG_IRAM, ll_cam_dma_isr, cam, &cam->cam_intr_handle);
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);
}

void ll_cam_do_vsync(cam_obj_t *cam)
Expand Down
122 changes: 77 additions & 45 deletions target/esp32s3/ll_cam.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#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"
Expand Down Expand Up @@ -87,7 +89,7 @@ void ll_cam_dma_reset(cam_obj_t *cam)
//GDMA.channel[cam->dma_num].in.wight.rx_weight = 7;//The weight of Rx channel 0-15
}

static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
static void CAMERA_ISR_IRAM_ATTR ll_cam_vsync_isr(void *arg)
{
//DBG_PIN_SET(1);
cam_obj_t *cam = (cam_obj_t *)arg;
Expand All @@ -110,7 +112,7 @@ static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
//DBG_PIN_SET(0);
}

static void IRAM_ATTR ll_cam_dma_isr(void *arg)
static void CAMERA_ISR_IRAM_ATTR ll_cam_dma_isr(void *arg)
{
cam_obj_t *cam = (cam_obj_t *)arg;
BaseType_t HPTaskAwoken = pdFALSE;
Expand Down Expand Up @@ -141,25 +143,6 @@ 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;
Expand Down Expand Up @@ -191,27 +174,72 @@ bool ll_cam_start(cam_obj_t *cam, int frame_pos)
return true;
}

static esp_err_t ll_cam_dma_init(cam_obj_t *cam)
esp_err_t ll_cam_deinit(cam_obj_t *cam)
{
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->cam_intr_handle) {
esp_intr_free(cam->cam_intr_handle);
cam->cam_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);
if (cam->dma_intr_handle) {
esp_intr_free(cam->dma_intr_handle);
cam->dma_intr_handle = NULL;
}
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;
}

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,
};
esp_err_t ret = gdma_new_channel(&rx_alloc_config, &cam->dma_channel_handle);
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);
}
// 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);
return ESP_OK;
}
Expand Down Expand Up @@ -267,12 +295,16 @@ 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 (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 (!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);
// }

LCD_CAM.cam_ctrl.val = 0;

Expand Down Expand Up @@ -369,7 +401,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 | ESP_INTR_FLAG_IRAM,
ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | CAMERA_ISR_IRAM_FLAG,
(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) {
Expand All @@ -378,7 +410,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 | ESP_INTR_FLAG_IRAM,
ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | CAMERA_ISR_IRAM_FLAG,
(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) {
Expand Down
14 changes: 14 additions & 0 deletions target/private_include/ll_cam.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@
#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
Expand Down Expand Up @@ -104,6 +115,9 @@ 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;
Expand Down

0 comments on commit f0bb429

Please sign in to comment.