mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spi: limit esp32 dma workaround only on esp32
This commit is contained in:
parent
c0ba33a99d
commit
9061efd3d1
@ -252,7 +252,8 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host);
|
|||||||
*/
|
*/
|
||||||
typedef void(*dmaworkaround_cb_t)(void *arg);
|
typedef void(*dmaworkaround_cb_t)(void *arg);
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
//This workaround is only for esp32
|
||||||
/**
|
/**
|
||||||
* @brief Request a reset for a certain DMA channel
|
* @brief Request a reset for a certain DMA channel
|
||||||
*
|
*
|
||||||
@ -307,6 +308,7 @@ void spicommon_dmaworkaround_idle(int dmachan);
|
|||||||
* @note This public API is deprecated.
|
* @note This public API is deprecated.
|
||||||
*/
|
*/
|
||||||
void spicommon_dmaworkaround_transfer_active(int dmachan);
|
void spicommon_dmaworkaround_transfer_active(int dmachan);
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Bus attributes
|
* Bus attributes
|
||||||
|
@ -783,11 +783,10 @@ static dmaworkaround_cb_t dmaworkaround_cb;
|
|||||||
static void *dmaworkaround_cb_arg;
|
static void *dmaworkaround_cb_arg;
|
||||||
static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
static int dmaworkaround_waiting_for_chan = 0;
|
static int dmaworkaround_waiting_for_chan = 0;
|
||||||
#endif
|
|
||||||
|
|
||||||
bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
|
bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
int otherchan = (dmachan == 1) ? 2 : 1;
|
int otherchan = (dmachan == 1) ? 2 : 1;
|
||||||
bool ret;
|
bool ret;
|
||||||
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
@ -804,24 +803,15 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t
|
|||||||
}
|
}
|
||||||
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
return ret;
|
return ret;
|
||||||
#else
|
|
||||||
//no need to reset
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
|
bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
return (dmaworkaround_waiting_for_chan != 0);
|
return (dmaworkaround_waiting_for_chan != 0);
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
dmaworkaround_channels_busy[dmachan-1] = 0;
|
dmaworkaround_channels_busy[dmachan-1] = 0;
|
||||||
if (dmaworkaround_waiting_for_chan == dmachan) {
|
if (dmaworkaround_waiting_for_chan == dmachan) {
|
||||||
@ -833,14 +823,12 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
|||||||
|
|
||||||
}
|
}
|
||||||
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
|
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
|
||||||
{
|
{
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
dmaworkaround_channels_busy[dmachan-1] = 1;
|
dmaworkaround_channels_busy[dmachan-1] = 1;
|
||||||
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
@ -609,10 +609,13 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
|||||||
//Okay, transaction is done.
|
//Okay, transaction is done.
|
||||||
const int cs = host->cur_cs;
|
const int cs = host->cur_cs;
|
||||||
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (bus_attr->dma_enabled) {
|
if (bus_attr->dma_enabled) {
|
||||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan);
|
spicommon_dmaworkaround_idle(bus_attr->tx_dma_chan);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
//cur_cs is changed to DEV_NUM_MAX here
|
//cur_cs is changed to DEV_NUM_MAX here
|
||||||
spi_post_trans(host);
|
spi_post_trans(host);
|
||||||
@ -662,11 +665,13 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
|||||||
|
|
||||||
if (trans_found) {
|
if (trans_found) {
|
||||||
spi_trans_priv_t *const cur_trans_buf = &host->cur_trans_buf;
|
spi_trans_priv_t *const cur_trans_buf = &host->cur_trans_buf;
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (bus_attr->dma_enabled && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) {
|
if (bus_attr->dma_enabled && (cur_trans_buf->buffer_to_rcv || cur_trans_buf->buffer_to_send)) {
|
||||||
//mark channel as active, so that the DMA will not be reset by the slave
|
//mark channel as active, so that the DMA will not be reset by the slave
|
||||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_transfer_active(bus_attr->tx_dma_chan);
|
spicommon_dmaworkaround_transfer_active(bus_attr->tx_dma_chan);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
spi_new_trans(device_to_send, cur_trans_buf);
|
spi_new_trans(device_to_send, cur_trans_buf);
|
||||||
}
|
}
|
||||||
// Exit of the ISR, handle interrupt re-enable (if sending transaction), retry (if there's coming BG),
|
// Exit of the ISR, handle interrupt re-enable (if sending transaction), retry (if there's coming BG),
|
||||||
@ -882,10 +887,14 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickT
|
|||||||
//configure the device ahead so that we don't need to do it again in the following transactions
|
//configure the device ahead so that we don't need to do it again in the following transactions
|
||||||
spi_setup_device(host->device[device->id]);
|
spi_setup_device(host->device[device->id]);
|
||||||
//the DMA is also occupied by the device, all the slave devices that using DMA should wait until bus released.
|
//the DMA is also occupied by the device, all the slave devices that using DMA should wait until bus released.
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (host->bus_attr->dma_enabled) {
|
if (host->bus_attr->dma_enabled) {
|
||||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_transfer_active(host->bus_attr->tx_dma_chan);
|
spicommon_dmaworkaround_transfer_active(host->bus_attr->tx_dma_chan);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,11 +908,13 @@ void SPI_MASTER_ISR_ATTR spi_device_release_bus(spi_device_t *dev)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (host->bus_attr->dma_enabled) {
|
if (host->bus_attr->dma_enabled) {
|
||||||
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
//This workaround is only for esp32, where tx_dma_chan and rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_idle(host->bus_attr->tx_dma_chan);
|
spicommon_dmaworkaround_idle(host->bus_attr->tx_dma_chan);
|
||||||
}
|
}
|
||||||
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
//allow clock to be lower than 80MHz when all tasks blocked
|
//allow clock to be lower than 80MHz when all tasks blocked
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
|
@ -325,11 +325,13 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_tr
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg)
|
static void SPI_SLAVE_ISR_ATTR spi_slave_restart_after_dmareset(void *arg)
|
||||||
{
|
{
|
||||||
spi_slave_t *host = (spi_slave_t *)arg;
|
spi_slave_t *host = (spi_slave_t *)arg;
|
||||||
esp_intr_enable(host->intr);
|
esp_intr_enable(host->intr);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
//This is run in interrupt context and apart from initialization and destruction, this is the only code
|
//This is run in interrupt context and apart from initialization and destruction, this is the only code
|
||||||
//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
|
//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
|
||||||
@ -352,18 +354,25 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
|||||||
spi_slave_hal_store_result(hal);
|
spi_slave_hal_store_result(hal);
|
||||||
host->cur_trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
|
host->cur_trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
//This workaround is only for esp32
|
||||||
if (spi_slave_hal_dma_need_reset(hal)) {
|
if (spi_slave_hal_dma_need_reset(hal)) {
|
||||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
//On ESP32, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_req_reset(host->tx_dma_chan, spi_slave_restart_after_dmareset, host);
|
spicommon_dmaworkaround_req_reset(host->tx_dma_chan, spi_slave_restart_after_dmareset, host);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
|
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
|
||||||
//Okay, transaction is done.
|
//Okay, transaction is done.
|
||||||
//Return transaction descriptor.
|
//Return transaction descriptor.
|
||||||
xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
|
xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
|
||||||
host->cur_trans = NULL;
|
host->cur_trans = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
//This workaround is only for esp32
|
||||||
if (use_dma) {
|
if (use_dma) {
|
||||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
//On ESP32, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_idle(host->tx_dma_chan);
|
spicommon_dmaworkaround_idle(host->tx_dma_chan);
|
||||||
if (spicommon_dmaworkaround_reset_in_progress()) {
|
if (spicommon_dmaworkaround_reset_in_progress()) {
|
||||||
//We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
|
//We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
|
||||||
@ -372,6 +381,7 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
//Disable interrupt before checking to avoid concurrency issue.
|
//Disable interrupt before checking to avoid concurrency issue.
|
||||||
esp_intr_disable(host->intr);
|
esp_intr_disable(host->intr);
|
||||||
@ -388,10 +398,13 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
|||||||
hal->rx_buffer = trans->rx_buffer;
|
hal->rx_buffer = trans->rx_buffer;
|
||||||
hal->tx_buffer = trans->tx_buffer;
|
hal->tx_buffer = trans->tx_buffer;
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if (use_dma) {
|
if (use_dma) {
|
||||||
//On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
//This workaround is only for esp32
|
||||||
|
//On ESP32, actual_tx_dma_chan and actual_rx_dma_chan are always same
|
||||||
spicommon_dmaworkaround_transfer_active(host->tx_dma_chan);
|
spicommon_dmaworkaround_transfer_active(host->tx_dma_chan);
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
spi_slave_hal_prepare_data(hal);
|
spi_slave_hal_prepare_data(hal);
|
||||||
|
|
||||||
|
@ -150,6 +150,7 @@ void spi_slave_hal_store_result(spi_slave_hal_context_t *hal);
|
|||||||
*/
|
*/
|
||||||
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
|
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
/**
|
/**
|
||||||
* Check whether we need to reset the DMA according to the status of last transactions.
|
* Check whether we need to reset the DMA according to the status of last transactions.
|
||||||
*
|
*
|
||||||
@ -161,3 +162,4 @@ uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
|
|||||||
* @return true if reset is needed, else false.
|
* @return true if reset is needed, else false.
|
||||||
*/
|
*/
|
||||||
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal);
|
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal);
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
@ -98,6 +98,8 @@ uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
|
|||||||
return hal->rcv_bitlen;
|
return hal->rcv_bitlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
//This workaround is only for esp32
|
||||||
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal)
|
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
@ -114,3 +116,4 @@ bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal)
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif //#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
Loading…
Reference in New Issue
Block a user