feature(spi_master): allow to place functions into IRAM to get higher efficiency

This commit is contained in:
Michael (XIAO Xufeng) 2018-06-11 19:54:18 +08:00 committed by michael
parent 59ab2136e8
commit 9c23b8e596
3 changed files with 49 additions and 7 deletions

View file

@ -1,4 +1,4 @@
#menu "Driver configurations"
menu "Driver configurations"
menu "ADC configuration"
@ -20,5 +20,30 @@ config ADC2_DISABLE_DAC
endmenu # ADC Configuration
#endmenu # Driver configurations
menu "SPI master configuration"
config SPI_MASTER_IN_IRAM
bool "Place transmitting functions of SPI master into IRAM"
default n
select SPI_MASTER_ISR_IN_IRAM
help
Normally only the ISR of SPI master is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
During unit test, this is enabled to measure the ideal case of api.
config SPI_MASTER_ISR_IN_IRAM
bool "Place SPI master ISR function into IRAM"
default y
help
Place the SPI master ISR in to IRAM to avoid possibly cache miss, or
being disabled during flash writing access.
endmenu # SPI Master Configuration
endmenu # Driver configurations

View file

@ -66,6 +66,18 @@ typedef typeof(SPI1.clock) spi_clock_reg_t;
#define NO_CS 3 //Number of CS pins per SPI host
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
#define SPI_MASTER_ISR_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ISR_ATTR
#endif
#ifdef CONFIG_SPI_MASTER_IN_IRAM
#define SPI_MASTER_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ATTR
#endif
/// struct to hold private transaction data (like tx and rx buffer for DMA).
typedef struct {
@ -179,7 +191,11 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
}
}
err = esp_intr_alloc(spicommon_irqsource_for_host(host), ESP_INTR_FLAG_INTRDISABLED, spi_intr, (void*)spihost[host], &spihost[host]->intr);
int flags = ESP_INTR_FLAG_INTRDISABLED;
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
flags |= ESP_INTR_FLAG_IRAM;
#endif
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void*)spihost[host], &spihost[host]->intr);
if (err != ESP_OK) {
ret = err;
goto cleanup;
@ -481,7 +497,7 @@ static inline void spi_set_clock(spi_dev_t *hw, spi_clock_reg_t reg) {
//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
//no muxes in this code.
static void IRAM_ATTR spi_intr(void *arg)
static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
{
int i;
BaseType_t r;
@ -730,7 +746,7 @@ static void IRAM_ATTR spi_intr(void *arg)
}
esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
{
esp_err_t ret = ESP_OK;
BaseType_t r;
@ -822,7 +838,7 @@ clean_up:
return ret;
}
esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)
esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)
{
BaseType_t r;
spi_trans_priv trans_buf;
@ -856,7 +872,7 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
}
//Porcelain to do one blocking transmission.
esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
esp_err_t ret;
spi_transaction_t *ret_trans;

View file

@ -27,3 +27,4 @@ CONFIG_SUPPORT_STATIC_ALLOCATION=y
CONFIG_ESP_TIMER_PROFILING=y
CONFIG_ADC2_DISABLE_DAC=n
CONFIG_WARN_WRITE_STRINGS=y
CONFIG_SPI_MASTER_IN_IRAM=y