Merge branch 'feat/csi_disclose_internal_buffer_api' into 'master'

feat(csi): add API to expose internal backup_buffer

Closes IDF-9572

See merge request espressif/esp-idf!30094
pull/13557/merge
Wan Lei 2024-04-17 14:51:55 +08:00
commit 624bcb4757
6 zmienionych plików z 128 dodań i 4 usunięć

Wyświetl plik

@ -42,6 +42,8 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_
static esp_err_t s_del_csi_ctlr(csi_controller_t *ctlr);
static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr);
static esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data);
static esp_err_t s_csi_ctlr_get_internal_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...);
static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len);
static esp_err_t s_csi_ctlr_enable(esp_cam_ctlr_handle_t ctlr);
static esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle);
static esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle);
@ -99,12 +101,17 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_
csi_controller_t *ctlr = heap_caps_calloc(1, sizeof(csi_controller_t), CSI_MEM_ALLOC_CAPS);
ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_NO_MEM, TAG, "no mem for csi controller context");
ret = s_csi_claim_controller(ctlr);
if (ret != ESP_OK) {
//claim fail, clean and return directly
free(ctlr);
ESP_RETURN_ON_ERROR(ret, TAG, "no available csi controller");
}
ESP_LOGD(TAG, "config->queue_items: %d", config->queue_items);
ctlr->trans_que = xQueueCreateWithCaps(config->queue_items, sizeof(esp_cam_ctlr_trans_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(ctlr->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue");
//claim a controller, then do assignment
ESP_GOTO_ON_ERROR(s_csi_claim_controller(ctlr), err, TAG, "no available csi controller");
#if SOC_ISP_SHARE_CSI_BRG
ESP_GOTO_ON_ERROR(mipi_csi_brg_claim(MIPI_CSI_BRG_USER_CSI, &ctlr->csi_brg_id), err, TAG, "csi bridge is in use already");
ctlr->csi_brg_in_use = true;
@ -207,6 +214,8 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_
ctlr->base.disable = s_csi_ctlr_disable;
ctlr->base.receive = s_ctlr_csi_receive;
ctlr->base.register_event_callbacks = s_register_event_callbacks;
ctlr->base.get_internal_buffer = s_csi_ctlr_get_internal_buffer;
ctlr->base.get_buffer_len = s_csi_ctlr_get_buffer_length;
*ret_handle = &(ctlr->base);
@ -251,6 +260,36 @@ static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr)
return ESP_OK;
}
static esp_err_t s_csi_ctlr_get_internal_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...)
{
csi_controller_t *csi_ctlr = __containerof(handle, csi_controller_t, base);
ESP_RETURN_ON_FALSE((csi_ctlr->csi_fsm >= CSI_FSM_INIT) && (csi_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver don't initialized or back_buffer not available");
ESP_RETURN_ON_FALSE(fb_num && fb_num <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number");
csi_ctlr->bk_buffer_exposed = true;
const void **fb_itor = fb0;
va_list args;
va_start(args, fb0);
for (uint32_t i = 0; i < fb_num; i++) {
if (fb_itor) {
*fb_itor = csi_ctlr->backup_buffer;
fb_itor = va_arg(args, const void **);
}
}
va_end(args);
return ESP_OK;
}
static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len)
{
csi_controller_t *csi_ctlr = __containerof(handle, csi_controller_t, base);
ESP_RETURN_ON_FALSE((csi_ctlr->csi_fsm >= CSI_FSM_INIT) && (csi_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver don't initialized or back_buffer not available");
*ret_fb_len = csi_ctlr->fb_size_in_bytes;
return ESP_OK;
}
static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data)
{
bool need_yield = false;
@ -306,7 +345,7 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_
dw_gdma_channel_config_transfer(chan, &csi_dma_transfer_config);
dw_gdma_channel_enable_ctrl(chan, true);
if (ctlr->trans.buffer != ctlr->backup_buffer) {
if ((ctlr->trans.buffer != ctlr->backup_buffer) || ctlr->bk_buffer_exposed) {
esp_err_t ret = esp_cache_msync((void *)(ctlr->trans.buffer), ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE);
assert(ret == ESP_OK);
assert(ctlr->cbs.on_trans_finished);

Wyświetl plik

@ -26,7 +26,7 @@ extern "C" {
#endif
typedef enum {
CSI_FSM_INIT,
CSI_FSM_INIT = 1,
CSI_FSM_ENABLED,
CSI_FSM_STARTED,
} csi_fsm_t;
@ -55,6 +55,7 @@ struct csi_controller_t {
size_t fb_size_in_bytes; //Frame buffer size, in bytes
esp_cam_ctlr_trans_t trans; //Saved done transaction to be given out to callers
void *backup_buffer; //backup buffer to make csi bridge can work to avoid wrong state
bool bk_buffer_exposed; //status of if back_buffer is exposed to users
QueueHandle_t trans_que; //transaction queue
esp_cam_ctlr_evt_cbs_t cbs; //user callbacks
void *cbs_user_data; //callback userdata

Wyświetl plik

@ -64,6 +64,25 @@ esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, co
return handle->register_event_callbacks(handle, cbs, user_data);
}
esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
ESP_RETURN_ON_FALSE(handle->get_internal_buffer, ESP_ERR_NOT_SUPPORTED, TAG, "get buffer function not supported");
va_list args;
va_start(args, fb0);
return handle->get_internal_buffer(handle, fb_num, fb0, args);
va_end(args);
}
esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len)
{
ESP_RETURN_ON_FALSE(handle && ret_fb_len, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
ESP_RETURN_ON_FALSE(handle->get_buffer_len, ESP_ERR_NOT_SUPPORTED, TAG, "get buffer length function not supported");
return handle->get_buffer_len(handle, ret_fb_len);
}
esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

Wyświetl plik

@ -102,6 +102,36 @@ esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle);
*/
esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data);
/**
* @brief Get ESP CAM controller internal malloced backup buffer(s) addr
*
* @note Generally, data in internal buffer is ready when `on_trans_finished` event
*
* @param[in] handle ESP CAM controller handle
* @param[in] fb_num Number of frame buffer(s) to get. This value must be the same as the number of the followed fbN parameters
* @param[out] fb0 Address of the frame buffer 0 (first frame buffer)
* @param[out] ... List of other frame buffers if any
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Invalid driver state
*/
esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...);
/**
* @brief Get ESP CAM controller internal backup buffer length
*
* @param[in] handle ESP CAM controller handle
* @param[out] ret_fb_len Optional, The size of each frame buffer, in bytes.
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG: NULL ptr
* - ESP_ERR_INVALID_STATE: Invalid driver state
*/
esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -105,6 +105,34 @@ struct esp_cam_ctlr_t {
*/
esp_err_t (*register_event_callbacks)(esp_cam_ctlr_t *ctlr, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_ctx);
/**
* @brief Get ESP CAM controller internal malloced backup buffer(s) addr
*
* @param[in] esp_cam_ctlr_t * ESP CAM controller handle
* @param[in] uint32_t Number of frame buffer(s) to get. This value must be the same as the number of the followed fbN parameters
* @param[out] const void ** Address of the frame buffer 0 (first frame buffer)
* @param[out] ... List of other frame buffers if any
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Invalid driver state
*/
esp_err_t (*get_internal_buffer)(esp_cam_ctlr_t *, uint32_t, const void **, ...);
/**
* @brief Get ESP CAM controller internal backup buffer length
*
* @param[in] esp_cam_ctlr_t * ESP CAM controller handle
* @param[out] size_t * The size of each frame buffer, in bytes.
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG: NULL ptr
* - ESP_ERR_INVALID_STATE: Invalid driver state
*/
esp_err_t (*get_buffer_len)(esp_cam_ctlr_t *, size_t *);
void *user_data; ///< User data
};

Wyświetl plik

@ -25,5 +25,12 @@ TEST_CASE("TEST CSI driver allocation", "[csi]")
esp_cam_ctlr_handle_t handle = NULL;
TEST_ESP_OK(esp_cam_new_csi_ctlr(&csi_config, &handle));
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_csi_ctlr(&csi_config, &handle));
uint8_t *bk_buffer = NULL;
size_t bk_buffer_len = 0;
TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer(handle, 1, (const void **)&bk_buffer));
TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len));
TEST_ASSERT_NOT_NULL(bk_buffer);
TEST_ASSERT_EQUAL((csi_config.h_res * csi_config.v_res * 2), bk_buffer_len); // out type RGB565 using 2 byte / pixel
TEST_ESP_OK(esp_cam_del_ctlr(handle));
}