mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 13:14:32 +02:00
spi_slave: add a flag SPI_SLAVE_NO_RETURN_RESULT to bypass return descriptor from ISR
if using this flag, driver willn't return the trans-done descriptor from ISR, so `spi_slave_get_trans_result()` shouldn't be called. besides, callback is the only way to know transaction status in that case, so a `post_trans_cb` will be checked mandatory.
This commit is contained in:
@@ -224,6 +224,7 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
|||||||
out.
|
out.
|
||||||
* @return
|
* @return
|
||||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||||
|
* - ESP_ERR_NOT_SUPPORTED if flag `SPI_DEVICE_NO_RETURN_RESULT` is set
|
||||||
* - ESP_ERR_TIMEOUT if there was no completed transaction before ticks_to_wait expired
|
* - ESP_ERR_TIMEOUT if there was no completed transaction before ticks_to_wait expired
|
||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
*/
|
*/
|
||||||
|
@@ -23,7 +23,7 @@ extern "C"
|
|||||||
#define SPI_SLAVE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
|
#define SPI_SLAVE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
|
||||||
#define SPI_SLAVE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
|
#define SPI_SLAVE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
|
||||||
#define SPI_SLAVE_BIT_LSBFIRST (SPI_SLAVE_TXBIT_LSBFIRST|SPI_SLAVE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
|
#define SPI_SLAVE_BIT_LSBFIRST (SPI_SLAVE_TXBIT_LSBFIRST|SPI_SLAVE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
|
||||||
|
#define SPI_SLAVE_NO_RETURN_RESULT (1<<2) ///< Don't return the descriptor to the host on completion (use `post_trans_cb` to notify instead)
|
||||||
|
|
||||||
typedef struct spi_slave_transaction_t spi_slave_transaction_t;
|
typedef struct spi_slave_transaction_t spi_slave_transaction_t;
|
||||||
typedef void(*slave_transaction_cb_t)(spi_slave_transaction_t *trans);
|
typedef void(*slave_transaction_cb_t)(spi_slave_transaction_t *trans);
|
||||||
@@ -158,6 +158,7 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
|
|||||||
* out.
|
* out.
|
||||||
* @return
|
* @return
|
||||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||||
|
* - ESP_ERR_NOT_SUPPORTED if flag `SPI_SLAVE_NO_RETURN_RESULT` is set
|
||||||
* - ESP_OK on success
|
* - ESP_OK on success
|
||||||
*/
|
*/
|
||||||
esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait);
|
esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait);
|
||||||
|
@@ -381,10 +381,16 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
|||||||
|
|
||||||
//Allocate queues, set defaults
|
//Allocate queues, set defaults
|
||||||
dev->trans_queue = xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv_t));
|
dev->trans_queue = xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv_t));
|
||||||
dev->ret_queue = xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv_t));
|
if (!dev->trans_queue) {
|
||||||
if (!dev->trans_queue || !dev->ret_queue) {
|
|
||||||
goto nomem;
|
goto nomem;
|
||||||
}
|
}
|
||||||
|
//ret_queue nolonger needed if use flag SPI_DEVICE_NO_RETURN_RESULT
|
||||||
|
if (!(dev_config->flags & SPI_DEVICE_NO_RETURN_RESULT)) {
|
||||||
|
dev->ret_queue = xQueueCreate(dev_config->queue_size, sizeof(spi_trans_priv_t));
|
||||||
|
if (!dev->ret_queue) {
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//We want to save a copy of the dev config in the dev struct.
|
//We want to save a copy of the dev config in the dev struct.
|
||||||
memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
|
memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
|
||||||
@@ -445,15 +451,17 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
|
|||||||
//catch design errors and aren't meant to be triggered during normal operation.
|
//catch design errors and aren't meant to be triggered during normal operation.
|
||||||
SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
||||||
SPI_CHECK(handle->host->cur_cs == DEV_NUM_MAX || handle->host->device[handle->host->cur_cs] != handle, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
SPI_CHECK(handle->host->cur_cs == DEV_NUM_MAX || handle->host->device[handle->host->cur_cs] != handle, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
||||||
|
if (handle->ret_queue) {
|
||||||
SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
//return
|
//return
|
||||||
int spics_io_num = handle->cfg.spics_io_num;
|
int spics_io_num = handle->cfg.spics_io_num;
|
||||||
if (spics_io_num >= 0) spicommon_cs_free_io(spics_io_num);
|
if (spics_io_num >= 0) spicommon_cs_free_io(spics_io_num);
|
||||||
|
|
||||||
//Kill queues
|
//Kill queues
|
||||||
vQueueDelete(handle->trans_queue);
|
if (handle->trans_queue) vQueueDelete(handle->trans_queue);
|
||||||
vQueueDelete(handle->ret_queue);
|
if (handle->ret_queue) vQueueDelete(handle->ret_queue);
|
||||||
spi_bus_lock_unregister_dev(handle->dev_lock);
|
spi_bus_lock_unregister_dev(handle->dev_lock);
|
||||||
|
|
||||||
assert(handle->host->device[handle->id] == handle);
|
assert(handle->host->device[handle->id] == handle);
|
||||||
@@ -852,6 +860,9 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle
|
|||||||
spi_trans_priv_t trans_buf;
|
spi_trans_priv_t trans_buf;
|
||||||
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
|
||||||
|
|
||||||
|
//if SPI_DEVICE_NO_RETURN_RESULT is set, ret_queue will always be empty
|
||||||
|
SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED);
|
||||||
|
|
||||||
//use the interrupt, block until return
|
//use the interrupt, block until return
|
||||||
r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
|
r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
@@ -125,6 +125,11 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
#endif
|
#endif
|
||||||
SPI_CHECK(slave_config->spics_io_num < 0 || GPIO_IS_VALID_GPIO(slave_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(slave_config->spics_io_num < 0 || GPIO_IS_VALID_GPIO(slave_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG);
|
||||||
|
|
||||||
|
//Check post_trans_cb status when `SPI_SLAVE_NO_RETURN_RESULT` flag is set.
|
||||||
|
if(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT) {
|
||||||
|
SPI_CHECK(slave_config->post_trans_cb != NULL, "use feature flag 'SPI_SLAVE_NO_RETURN_RESULT' but no post_trans_cb function sets", ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
|
spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
|
||||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||||
|
|
||||||
@@ -183,11 +188,17 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
|
|
||||||
//Create queues
|
//Create queues
|
||||||
spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
|
spihost[host]->trans_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
|
||||||
spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
|
if (!spihost[host]->trans_queue) {
|
||||||
if (!spihost[host]->trans_queue || !spihost[host]->ret_queue) {
|
|
||||||
ret = ESP_ERR_NO_MEM;
|
ret = ESP_ERR_NO_MEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
if(!(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT)) {
|
||||||
|
spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_transaction_t *));
|
||||||
|
if (!spihost[host]->ret_queue) {
|
||||||
|
ret = ESP_ERR_NO_MEM;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
||||||
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
|
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
|
||||||
@@ -298,6 +309,9 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_
|
|||||||
BaseType_t r;
|
BaseType_t r;
|
||||||
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||||
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
||||||
|
//if SPI_SLAVE_NO_RETURN_RESULT is set, ret_queue will always be empty
|
||||||
|
SPI_CHECK(!(spihost[host]->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED);
|
||||||
|
|
||||||
r = xQueueReceive(spihost[host]->ret_queue, (void *)trans_desc, ticks_to_wait);
|
r = xQueueReceive(spihost[host]->ret_queue, (void *)trans_desc, ticks_to_wait);
|
||||||
if (!r) return ESP_ERR_TIMEOUT;
|
if (!r) return ESP_ERR_TIMEOUT;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -349,9 +363,10 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
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.
|
|
||||||
//Return transaction descriptor.
|
if(!(host->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT)) {
|
||||||
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 (use_dma) {
|
if (use_dma) {
|
||||||
|
Reference in New Issue
Block a user