forked from espressif/esp-idf
Merge branch 'contrib/github_pr_11499' into 'master'
Implement descriptor error callback for GDMA (GitHub PR) Closes IDFGH-10236 See merge request espressif/esp-idf!23934
This commit is contained in:
@@ -391,6 +391,9 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
|
|||||||
if (cbs->on_trans_eof) {
|
if (cbs->on_trans_eof) {
|
||||||
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM");
|
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM");
|
||||||
}
|
}
|
||||||
|
if (cbs->on_descr_err) {
|
||||||
|
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_descr_err), ESP_ERR_INVALID_ARG, err, TAG, "on_descr_err not in IRAM");
|
||||||
|
}
|
||||||
if (user_data) {
|
if (user_data) {
|
||||||
ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
|
ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
|
||||||
}
|
}
|
||||||
@@ -402,9 +405,11 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
|
|||||||
// enable/disable GDMA interrupt events for TX channel
|
// enable/disable GDMA interrupt events for TX channel
|
||||||
portENTER_CRITICAL(&pair->spinlock);
|
portENTER_CRITICAL(&pair->spinlock);
|
||||||
gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_TX_EOF, cbs->on_trans_eof != NULL);
|
gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_TX_EOF, cbs->on_trans_eof != NULL);
|
||||||
|
gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_TX_DESC_ERROR, cbs->on_descr_err != NULL);
|
||||||
portEXIT_CRITICAL(&pair->spinlock);
|
portEXIT_CRITICAL(&pair->spinlock);
|
||||||
|
|
||||||
tx_chan->on_trans_eof = cbs->on_trans_eof;
|
tx_chan->on_trans_eof = cbs->on_trans_eof;
|
||||||
|
tx_chan->on_descr_err = cbs->on_descr_err;
|
||||||
tx_chan->user_data = user_data;
|
tx_chan->user_data = user_data;
|
||||||
|
|
||||||
ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed");
|
ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed");
|
||||||
@@ -427,6 +432,9 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
|
|||||||
if (cbs->on_recv_eof) {
|
if (cbs->on_recv_eof) {
|
||||||
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM");
|
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM");
|
||||||
}
|
}
|
||||||
|
if (cbs->on_descr_err) {
|
||||||
|
ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_descr_err), ESP_ERR_INVALID_ARG, err, TAG, "on_descr_err not in IRAM");
|
||||||
|
}
|
||||||
if (user_data) {
|
if (user_data) {
|
||||||
ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
|
ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM");
|
||||||
}
|
}
|
||||||
@@ -438,9 +446,11 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
|
|||||||
// enable/disable GDMA interrupt events for RX channel
|
// enable/disable GDMA interrupt events for RX channel
|
||||||
portENTER_CRITICAL(&pair->spinlock);
|
portENTER_CRITICAL(&pair->spinlock);
|
||||||
gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_RX_SUC_EOF, cbs->on_recv_eof != NULL);
|
gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_RX_SUC_EOF, cbs->on_recv_eof != NULL);
|
||||||
|
gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_RX_DESC_ERROR, cbs->on_descr_err != NULL);
|
||||||
portEXIT_CRITICAL(&pair->spinlock);
|
portEXIT_CRITICAL(&pair->spinlock);
|
||||||
|
|
||||||
rx_chan->on_recv_eof = cbs->on_recv_eof;
|
rx_chan->on_recv_eof = cbs->on_recv_eof;
|
||||||
|
rx_chan->on_descr_err = cbs->on_descr_err;
|
||||||
rx_chan->user_data = user_data;
|
rx_chan->user_data = user_data;
|
||||||
|
|
||||||
ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed");
|
ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed");
|
||||||
@@ -726,6 +736,13 @@ static void IRAM_ATTR gdma_default_rx_isr(void *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (intr_status & GDMA_LL_EVENT_RX_DESC_ERROR) {
|
||||||
|
if (rx_chan && rx_chan->on_descr_err) {
|
||||||
|
if (rx_chan->on_descr_err(&rx_chan->base, NULL, rx_chan->user_data)) {
|
||||||
|
need_yield = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (need_yield) {
|
if (need_yield) {
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
@@ -753,7 +770,13 @@ static void IRAM_ATTR gdma_default_tx_isr(void *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (intr_status & GDMA_LL_EVENT_TX_DESC_ERROR) {
|
||||||
|
if (tx_chan && tx_chan->on_descr_err) {
|
||||||
|
if (tx_chan->on_descr_err(&tx_chan->base, NULL, tx_chan->user_data)) {
|
||||||
|
need_yield = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (need_yield) {
|
if (need_yield) {
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
@@ -76,12 +76,14 @@ struct gdma_tx_channel_t {
|
|||||||
gdma_channel_t base; // GDMA channel, base class
|
gdma_channel_t base; // GDMA channel, base class
|
||||||
void *user_data; // user registered DMA event data
|
void *user_data; // user registered DMA event data
|
||||||
gdma_event_callback_t on_trans_eof; // TX EOF callback
|
gdma_event_callback_t on_trans_eof; // TX EOF callback
|
||||||
|
gdma_event_callback_t on_descr_err; // Descriptor error callback
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gdma_rx_channel_t {
|
struct gdma_rx_channel_t {
|
||||||
gdma_channel_t base; // GDMA channel, base class
|
gdma_channel_t base; // GDMA channel, base class
|
||||||
void *user_data; // user registered DMA event data
|
void *user_data; // user registered DMA event data
|
||||||
gdma_event_callback_t on_recv_eof; // RX EOF callback
|
gdma_event_callback_t on_recv_eof; // RX EOF callback
|
||||||
|
gdma_event_callback_t on_descr_err; // Descriptor error callback
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -52,7 +52,6 @@ typedef struct {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of GDMA event data
|
* @brief Type of GDMA event data
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
@@ -64,31 +63,30 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* @brief Type of GDMA event callback
|
* @brief Type of GDMA event callback
|
||||||
* @param dma_chan GDMA channel handle, created from `gdma_new_channel`
|
* @param dma_chan GDMA channel handle, created from `gdma_new_channel`
|
||||||
* @param event_data GDMA event data
|
* @param event_data GDMA event data. Different event share the same data structure, but the caller may only use a few or none of the data members.
|
||||||
* @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`
|
* @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`
|
||||||
*
|
*
|
||||||
* @return Whether a task switch is needed after the callback function returns,
|
* @return Whether a task switch is needed after the callback function returns,
|
||||||
* this is usually due to the callback wakes up some high priority task.
|
* this is usually due to the callback wakes up some high priority task.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
|
typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Group of supported GDMA TX callbacks
|
* @brief Group of supported GDMA TX callbacks
|
||||||
* @note The callbacks are all running under ISR environment
|
* @note The callbacks are all running under ISR environment
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */
|
gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */
|
||||||
|
gdma_event_callback_t on_descr_err; /*!< Invoked when DMA encounters a descriptor error */
|
||||||
} gdma_tx_event_callbacks_t;
|
} gdma_tx_event_callbacks_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Group of supported GDMA RX callbacks
|
* @brief Group of supported GDMA RX callbacks
|
||||||
* @note The callbacks are all running under ISR environment
|
* @note The callbacks are all running under ISR environment
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */
|
gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */
|
||||||
|
gdma_event_callback_t on_descr_err; /*!< Invoked when DMA encounters a descriptor error */
|
||||||
} gdma_rx_event_callbacks_t;
|
} gdma_rx_event_callbacks_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user