mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 20:54:32 +02:00
Merge branch 'fix/jpeg_dma_stuck' into 'master'
fix(jpeg): use dma2d empty rx desc event to avoid a stuck on bad quality image See merge request espressif/esp-idf!37693
This commit is contained in:
@@ -26,7 +26,7 @@ endif()
|
|||||||
if(${target} STREQUAL "linux")
|
if(${target} STREQUAL "linux")
|
||||||
set(priv_requires "")
|
set(priv_requires "")
|
||||||
else()
|
else()
|
||||||
set(priv_requires esp_mm esp_pm)
|
set(priv_requires esp_mm esp_pm esp_psram)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -261,6 +261,12 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_
|
|||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_DESC_EMPTY) {
|
||||||
|
ESP_LOGE(TAG, "Due to image quality issues, the generated image is larger than the buffer provided by the user. You can increase the buffer or ignore this information");
|
||||||
|
ret = ESP_ERR_INVALID_STATE;
|
||||||
|
goto err2; // dma2d will freeup this channel in this event, so goto err2
|
||||||
|
}
|
||||||
|
|
||||||
if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_EOF) {
|
if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_EOF) {
|
||||||
ESP_GOTO_ON_ERROR(esp_cache_msync((void*)encoder_engine->rxlink, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err1, TAG, "sync memory to cache failed");
|
ESP_GOTO_ON_ERROR(esp_cache_msync((void*)encoder_engine->rxlink, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err1, TAG, "sync memory to cache failed");
|
||||||
compressed_size = s_dma_desc_get_len(encoder_engine->rxlink);
|
compressed_size = s_dma_desc_get_len(encoder_engine->rxlink);
|
||||||
@@ -367,6 +373,19 @@ static bool s_jpeg_rx_eof(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t
|
|||||||
return higher_priority_task_awoken;
|
return higher_priority_task_awoken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool s_jpeg_rx_desc_empty(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data)
|
||||||
|
{
|
||||||
|
jpeg_encoder_handle_t encoder_engine = (jpeg_encoder_handle_t) user_data;
|
||||||
|
portBASE_TYPE higher_priority_task_awoken = pdFALSE;
|
||||||
|
jpeg_enc_dma2d_evt_t s_event = {
|
||||||
|
.dma_evt = JPEG_DMA2D_RX_DESC_EMPTY,
|
||||||
|
.encoder_status = 0,
|
||||||
|
};
|
||||||
|
xQueueSendFromISR(encoder_engine->evt_queue, &s_event, &higher_priority_task_awoken);
|
||||||
|
|
||||||
|
return higher_priority_task_awoken;
|
||||||
|
}
|
||||||
|
|
||||||
static void jpeg_enc_config_dma_trans_ability(jpeg_encoder_handle_t encoder_engine)
|
static void jpeg_enc_config_dma_trans_ability(jpeg_encoder_handle_t encoder_engine)
|
||||||
{
|
{
|
||||||
// set transfer ability
|
// set transfer ability
|
||||||
@@ -442,6 +461,7 @@ static bool s_jpeg_enc_transaction_on_job_picked(uint32_t channel_num, const dma
|
|||||||
|
|
||||||
static dma2d_rx_event_callbacks_t jpeg_dec_cbs = {
|
static dma2d_rx_event_callbacks_t jpeg_dec_cbs = {
|
||||||
.on_recv_eof = s_jpeg_rx_eof,
|
.on_recv_eof = s_jpeg_rx_eof,
|
||||||
|
.on_desc_empty = s_jpeg_rx_desc_empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
dma2d_register_rx_event_callbacks(rx_chan, &jpeg_dec_cbs, encoder_engine);
|
dma2d_register_rx_event_callbacks(rx_chan, &jpeg_dec_cbs, encoder_engine);
|
||||||
|
@@ -118,6 +118,7 @@ typedef enum {
|
|||||||
JPEG_DMA2D_RX_EOF = BIT(0), // DMA2D rx eof event
|
JPEG_DMA2D_RX_EOF = BIT(0), // DMA2D rx eof event
|
||||||
JPEG_DMA2D_RX_DONE = BIT(1), // DMA2D rx done event
|
JPEG_DMA2D_RX_DONE = BIT(1), // DMA2D rx done event
|
||||||
JPEG_DMA2D_TX_DONE = BIT(2), // DMA2D tx done event
|
JPEG_DMA2D_TX_DONE = BIT(2), // DMA2D tx done event
|
||||||
|
JPEG_DMA2D_RX_DESC_EMPTY = BIT(3), // DMA2D rx empty event
|
||||||
} jpeg_dma2d_evt_enum_t;
|
} jpeg_dma2d_evt_enum_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -298,8 +298,14 @@ static NOINLINE_ATTR bool _dma2d_default_rx_isr(dma2d_group_t *group, int channe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (intr_status & DMA2D_LL_EVENT_RX_DESC_EMPTY) {
|
||||||
|
if (rx_chan->on_desc_empty) {
|
||||||
|
need_yield |= rx_chan->on_desc_empty(&rx_chan->base, &edata, user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If last transaction completes (regardless success or not), free the channels
|
// If last transaction completes (regardless success or not), free the channels
|
||||||
if (intr_status & (DMA2D_LL_EVENT_RX_SUC_EOF | DMA2D_LL_EVENT_RX_ERR_EOF | DMA2D_LL_EVENT_RX_DESC_ERROR)) {
|
if (intr_status & (DMA2D_LL_EVENT_RX_SUC_EOF | DMA2D_LL_EVENT_RX_ERR_EOF | DMA2D_LL_EVENT_RX_DESC_ERROR | DMA2D_LL_EVENT_RX_DESC_EMPTY)) {
|
||||||
if (!(intr_status & DMA2D_LL_EVENT_RX_ERR_EOF)) {
|
if (!(intr_status & DMA2D_LL_EVENT_RX_ERR_EOF)) {
|
||||||
assert(dma2d_ll_rx_is_fsm_idle(group->hal.dev, channel_id));
|
assert(dma2d_ll_rx_is_fsm_idle(group->hal.dev, channel_id));
|
||||||
}
|
}
|
||||||
@@ -688,6 +694,10 @@ esp_err_t dma2d_register_rx_event_callbacks(dma2d_channel_handle_t dma2d_chan, d
|
|||||||
rx_chan->on_desc_done = cbs->on_desc_done;
|
rx_chan->on_desc_done = cbs->on_desc_done;
|
||||||
mask |= DMA2D_LL_EVENT_RX_DONE;
|
mask |= DMA2D_LL_EVENT_RX_DONE;
|
||||||
}
|
}
|
||||||
|
if (cbs->on_desc_empty) {
|
||||||
|
rx_chan->on_desc_empty = cbs->on_desc_empty;
|
||||||
|
mask |= DMA2D_LL_EVENT_RX_DESC_EMPTY;
|
||||||
|
}
|
||||||
rx_chan->user_data = user_data;
|
rx_chan->user_data = user_data;
|
||||||
dma2d_ll_rx_enable_interrupt(group->hal.dev, rx_chan->base.channel_id, mask, true);
|
dma2d_ll_rx_enable_interrupt(group->hal.dev, rx_chan->base.channel_id, mask, true);
|
||||||
|
|
||||||
|
@@ -86,6 +86,7 @@ struct dma2d_rx_channel_t {
|
|||||||
void *user_data; // User registered DMA event data
|
void *user_data; // User registered DMA event data
|
||||||
dma2d_event_callback_t on_recv_eof; // RX EOF event callback
|
dma2d_event_callback_t on_recv_eof; // RX EOF event callback
|
||||||
dma2d_event_callback_t on_desc_done; // RX DONE event callback
|
dma2d_event_callback_t on_desc_done; // RX DONE event callback
|
||||||
|
dma2d_event_callback_t on_desc_empty; // RX desc empty callback, trigger when buffer on dma is not sufficient.
|
||||||
uint32_t bundled_tx_channel_mask; // Bit mask indicating the TX channels together with the RX channel to do the transaction
|
uint32_t bundled_tx_channel_mask; // Bit mask indicating the TX channels together with the RX channel to do the transaction
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -344,6 +344,8 @@ typedef struct {
|
|||||||
to be still in the middle of a complete transaction (partially done),
|
to be still in the middle of a complete transaction (partially done),
|
||||||
you are allowed to configure 2D-DMA channel hardware/descriptor in this
|
you are allowed to configure 2D-DMA channel hardware/descriptor in this
|
||||||
callback, and let the channels start running again */
|
callback, and let the channels start running again */
|
||||||
|
dma2d_event_callback_t on_desc_empty; /*!< Invoked when the buffer size pointed to by the received linked list
|
||||||
|
descriptor is less than the length of the data to be received */
|
||||||
} dma2d_rx_event_callbacks_t;
|
} dma2d_rx_event_callbacks_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user