From a52ab8ca873db495116b56e7bbe780c50ab5a747 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 13 Nov 2018 11:02:54 +0800 Subject: [PATCH 1/2] spi_master: modify the error msg a little when over freq limit The MISO signal will be delayed if the GPIO matrix is enabled. However, delay also comes from the slave. Previous code only considers the former case, and assume the frequency limitations is only violated when GPIO matrix is used. Now we are able to calculate the freq limit when extenal MISO delay is given (feature introduced in 9c6c6ec34ab0641ace89aeb9b1a133eb6fae1a18). The frequency limit is lower when the external MISO delay is large, and the limit is likely to be violated even with IOMUX. Resolves https://github.com/espressif/esp-idf/issues/2690. --- components/driver/spi_master.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index a291825920..7d8932f5e1 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -442,14 +442,14 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_ duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos; eff_clk = spi_cal_clock(apbclk, dev_config->clock_speed_hz, duty_cycle, (uint32_t*)&clk_reg); int freq_limit = spi_get_freq_limit(!(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS), dev_config->input_delay_ns); - //GPIO matrix can only change data at 80Mhz rate, which only allows 40MHz SPI clock. - SPI_CHECK(eff_clk <= 40*1000*1000 || spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS, "80MHz only supported on iomux pins", ESP_ERR_INVALID_ARG); + //Speed >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. spi_get_timing(!(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS), dev_config->input_delay_ns, eff_clk, &dummy_required, &miso_delay); SPI_CHECK( dev_config->flags & SPI_DEVICE_HALFDUPLEX || dummy_required == 0 || dev_config->flags & SPI_DEVICE_NO_DUMMY, -"When GPIO matrix is used in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\ -Please note the SPI can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\ +"When work in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\ +Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode.\n\ +Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\ Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output data at higher speed, or read data at your own risk.", ESP_ERR_INVALID_ARG, freq_limit/1000./1000 ); From 26626dfbf2ffc597c1d9e3f504743c7d71ec8851 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 13 Nov 2018 11:09:13 +0800 Subject: [PATCH 2/2] spi: add documents explicitly showing the executing core of the ISR It is an ESP specific FreeRTOS feature that the ISR is always executed on the core which calls the interrupt register function. In the SPI driver, the function is always called in the bus initialization function. Hence, the ISR will be executed on the core which initialize the driver. If the core is starved due to higher priority ISRs, or the interrupt is disabled on the core (spinlock called, etc.), the ISR will not get executed and SPI transactions will not be handled. (MINOR CHANGE) Resolves https://github.com/espressif/esp-idf/issues/2432. --- components/driver/include/driver/spi_master.h | 4 +++ components/driver/include/driver/spi_slave.h | 26 +++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index ca82468890..04f2ba1f23 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -150,6 +150,10 @@ typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in * DMA-capable memory. * + * @warning The ISR of SPI is always executed on the core which calls this + * function. Never starve the ISR on this core or the SPI transactions will not + * be handled. + * * @return * - ESP_ERR_INVALID_ARG if configuration is invalid * - ESP_ERR_INVALID_STATE if host already is in use diff --git a/components/driver/include/driver/spi_slave.h b/components/driver/include/driver/spi_slave.h index 9ad4b9126d..ba0ce1de69 100644 --- a/components/driver/include/driver/spi_slave.h +++ b/components/driver/include/driver/spi_slave.h @@ -71,10 +71,14 @@ struct spi_slave_transaction_t { * it. The SPI hardware has two DMA channels to share. This parameter indicates which * one to use. * - * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in + * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in * DMA-capable memory. * - * @return + * @warning The ISR of SPI is always executed on the core which calls this + * function. Never starve the ISR on this core or the SPI transactions will not + * be handled. + * + * @return * - ESP_ERR_INVALID_ARG if configuration is invalid * - ESP_ERR_INVALID_STATE if host already is in use * - ESP_ERR_NO_MEM if out of memory @@ -86,7 +90,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b * @brief Free a SPI bus claimed as a SPI slave interface * * @param host SPI peripheral to free - * @return + * @return * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_ERR_INVALID_STATE if not all devices on the bus are freed * - ESP_OK on success @@ -110,7 +114,7 @@ esp_err_t spi_slave_free(spi_host_device_t host); * into the transaction description. * @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to * never time out. - * @return + * @return * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_OK on success */ @@ -120,19 +124,19 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact /** * @brief Get the result of a SPI transaction queued earlier * - * This routine will wait until a transaction to the given device (queued earlier with + * This routine will wait until a transaction to the given device (queued earlier with * spi_slave_queue_trans) has succesfully completed. It will then return the description of the - * completed transaction so software can inspect the result and e.g. free the memory or + * completed transaction so software can inspect the result and e.g. free the memory or * re-use the buffers. * * It is mandatory to eventually use this function for any transaction queued by ``spi_slave_queue_trans``. * * @param host SPI peripheral to that is acting as a slave - * @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the + * @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the * transaction that is executed * @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time * out. - * @return + * @return * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_OK on success */ @@ -143,16 +147,16 @@ esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transacti * @brief Do a SPI transaction * * Essentially does the same as spi_slave_queue_trans followed by spi_slave_get_trans_result. Do - * not use this when there is still a transaction queued that hasn't been finalized + * not use this when there is still a transaction queued that hasn't been finalized * using spi_slave_get_trans_result. * * @param host SPI peripheral to that is acting as a slave - * @param trans_desc Pointer to variable able to contain a pointer to the description of the + * @param trans_desc Pointer to variable able to contain a pointer to the description of the * transaction that is executed. Not const because we may want to write status back * into the transaction description. * @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time * out. - * @return + * @return * - ESP_ERR_INVALID_ARG if parameter is invalid * - ESP_OK on success */