Skip to content

Commit ef1c0da

Browse files
committed
feat: add PSRAM-DMA flag + runtime API for ESP32-S2/S3; remove 16MHz heuristic
Add a Kconfig switch (CONFIG_CAMERA_PSRAM_DMA) to enable camera to PSRAM DMA copy on ESP32-S2 and ESP32-S3 targets, in favor of removing the undocumented "set XCLK=16MHz to enable PSRAM DMA" heuristic. cam_hal.c: - Select psram_mode = true when CONFIG_CAMERA_PSRAM_DMA && target is S2/S3. - Otherwise psram_mode = false. - Log whether PSRAM DMA mode is enabled. Kconfig: - New bool CAMERA_PSRAM_DMA (default n) under Camera configuration. Runtime control: - New public API: - esp_camera_set_psram_mode(bool enable) - esp_camera_get_psram_mode(void) - esp_camera_reconfigure(const camera_config_t *cfg) README/test: - Remove stale 16MHz XCLK comments. - Add short note describing CONFIG_CAMERA_PSRAM_DMA.
1 parent eea6573 commit ef1c0da

File tree

7 files changed

+94
-6
lines changed

7 files changed

+94
-6
lines changed

Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ menu "Camera configuration"
214214
Maximum value of DMA buffer
215215
Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent.
216216

217+
config CAMERA_PSRAM_DMA
218+
bool "Enable PSRAM DMA mode by default"
219+
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
220+
default n
221+
help
222+
Enable DMA transfers directly from PSRAM on supported targets
223+
(ESP32-S2 and ESP32-S3) by default.
224+
217225
choice CAMERA_JPEG_MODE_FRAME_SIZE_OPTION
218226
prompt "JPEG mode frame size option"
219227
default CAMERA_JPEG_MODE_FRAME_SIZE_AUTO

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ This repository hosts ESP32 series Soc compatible driver for image sensors. Addi
3838
- 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`.
3939
- 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.
4040
- 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.
41+
- The Kconfig option `CONFIG_CAMERA_PSRAM_DMA` enables PSRAM DMA mode on ESP32-S2 and ESP32-S3 devices. This flag defaults to false.
42+
- You can switch PSRAM DMA mode at runtime using `esp_camera_set_psram_mode()`.
4143

4244
## Installation Instructions
4345

@@ -135,7 +137,7 @@ static camera_config_t camera_config = {
135137
.pin_href = CAM_PIN_HREF,
136138
.pin_pclk = CAM_PIN_PCLK,
137139

138-
.xclk_freq_hz = 20000000,//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
140+
.xclk_freq_hz = 20000000,
139141
.ledc_timer = LEDC_TIMER_0,
140142
.ledc_channel = LEDC_CHANNEL_0,
141143

driver/cam_hal.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <string.h>
1717
#include <stdalign.h>
1818
#include "esp_heap_caps.h"
19+
#include "freertos/FreeRTOS.h"
1920
#include "ll_cam.h"
2021
#include "cam_hal.h"
2122

@@ -41,6 +42,8 @@
4142

4243
static const char *TAG = "cam_hal";
4344
static cam_obj_t *cam_obj = NULL;
45+
static volatile bool g_psram_dma_mode = CONFIG_CAMERA_PSRAM_DMA;
46+
static portMUX_TYPE g_psram_dma_lock = portMUX_INITIALIZER_UNLOCKED;
4447

4548
/* At top of cam_hal.c – one switch for noisy ISR prints */
4649
#ifndef CAM_LOG_SPAM_EVERY_FRAME
@@ -411,11 +414,12 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
411414
CAM_CHECK_GOTO(ret == ESP_OK, "ll_cam_set_sample_mode failed", err);
412415

413416
cam_obj->jpeg_mode = config->pixel_format == PIXFORMAT_JPEG;
414-
#if CONFIG_IDF_TARGET_ESP32
415-
cam_obj->psram_mode = false;
417+
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
418+
cam_obj->psram_mode = g_psram_dma_mode;
416419
#else
417-
cam_obj->psram_mode = (config->xclk_freq_hz == 16000000);
420+
cam_obj->psram_mode = false;
418421
#endif
422+
ESP_LOGI(TAG, "PSRAM DMA mode %s", cam_obj->psram_mode ? "enabled" : "disabled");
419423
cam_obj->frame_cnt = config->fb_count;
420424
cam_obj->width = resolution[frame_size].width;
421425
cam_obj->height = resolution[frame_size].height;
@@ -612,3 +616,15 @@ bool cam_get_available_frames(void)
612616
{
613617
return 0 < uxQueueMessagesWaiting(cam_obj->frame_buffer_queue);
614618
}
619+
620+
void cam_set_psram_mode(bool enable)
621+
{
622+
portENTER_CRITICAL(&g_psram_dma_lock);
623+
g_psram_dma_mode = enable;
624+
portEXIT_CRITICAL(&g_psram_dma_lock);
625+
}
626+
627+
bool cam_get_psram_mode(void)
628+
{
629+
return g_psram_dma_mode;
630+
}

driver/esp_camera.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ typedef struct {
9595
static const char *CAMERA_SENSOR_NVS_KEY = "sensor";
9696
static const char *CAMERA_PIXFORMAT_NVS_KEY = "pixformat";
9797
static camera_state_t *s_state = NULL;
98+
static camera_config_t s_saved_config;
9899

99100
#if CONFIG_IDF_TARGET_ESP32S3 // LCD_CAM module of ESP32-S3 will generate xclk
100101
#define CAMERA_ENABLE_OUT_CLOCK(v)
@@ -298,6 +299,7 @@ static pixformat_t get_output_data_format(camera_conv_mode_t conv_mode)
298299
esp_err_t esp_camera_init(const camera_config_t *config)
299300
{
300301
esp_err_t err;
302+
s_saved_config = *config;
301303
err = cam_init(config);
302304
if (err != ESP_OK) {
303305
ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
@@ -517,3 +519,32 @@ bool esp_camera_available_frames(void)
517519
}
518520
return cam_get_available_frames();
519521
}
522+
523+
esp_err_t esp_camera_reconfigure(const camera_config_t *config)
524+
{
525+
if (!config) {
526+
return ESP_ERR_INVALID_ARG;
527+
}
528+
if (s_state) {
529+
esp_err_t err = esp_camera_deinit();
530+
if (err != ESP_OK) {
531+
return err;
532+
}
533+
}
534+
s_saved_config = *config;
535+
return esp_camera_init(&s_saved_config);
536+
}
537+
538+
esp_err_t esp_camera_set_psram_mode(bool enable)
539+
{
540+
cam_set_psram_mode(enable);
541+
if (!s_state) {
542+
return ESP_ERR_INVALID_STATE;
543+
}
544+
return esp_camera_reconfigure(&s_saved_config);
545+
}
546+
547+
bool esp_camera_get_psram_mode(void)
548+
{
549+
return cam_get_psram_mode();
550+
}

driver/include/esp_camera.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ typedef struct {
138138
int pin_href; /*!< GPIO pin for camera HREF line */
139139
int pin_pclk; /*!< GPIO pin for camera PCLK line */
140140

141-
int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode */
141+
int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. */
142142

143143
ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */
144144
ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */
@@ -245,6 +245,35 @@ void esp_camera_return_all(void);
245245
*/
246246
bool esp_camera_available_frames(void);
247247

248+
/**
249+
* @brief Enable or disable PSRAM DMA mode at runtime.
250+
*
251+
* @param enable True to enable PSRAM DMA mode, false to disable it.
252+
* @return
253+
* - ESP_OK on success
254+
* - ESP_ERR_INVALID_STATE if the camera is not initialized
255+
* - Propagated error from reinitialization on failure
256+
*/
257+
esp_err_t esp_camera_set_psram_mode(bool enable);
258+
259+
/**
260+
* @brief Reinitialize the camera with a new configuration.
261+
*
262+
* @param config Updated camera configuration structure
263+
* @return
264+
* - ESP_OK on success
265+
* - ESP_ERR_INVALID_ARG if config is NULL
266+
* - Propagated error from deinit or init if they fail
267+
*/
268+
esp_err_t esp_camera_reconfigure(const camera_config_t *config);
269+
270+
/**
271+
* @brief Get current PSRAM DMA mode state.
272+
*
273+
* @return True if PSRAM DMA is enabled, false otherwise.
274+
*/
275+
bool esp_camera_get_psram_mode(void);
276+
248277

249278
#ifdef __cplusplus
250279
}

driver/private_include/cam_hal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ void cam_give_all(void);
5959

6060
bool cam_get_available_frames(void);
6161

62+
void cam_set_psram_mode(bool enable);
63+
bool cam_get_psram_mode(void);
64+
6265
#ifdef __cplusplus
6366
}
6467
#endif

test/test_camera.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, fr
144144
.pin_href = HREF_GPIO_NUM,
145145
.pin_pclk = PCLK_GPIO_NUM,
146146

147-
//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
148147
.xclk_freq_hz = xclk_freq_hz,
149148
.ledc_timer = LEDC_TIMER_0,
150149
.ledc_channel = LEDC_CHANNEL_0,

0 commit comments

Comments
 (0)