From a6e14c37b26273e60f2b5e5761f261df1648811c Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Thu, 13 May 2021 11:53:44 +0800 Subject: [PATCH] SPI: chip select can now be kept active if the bus has been acquired The user can now request the chip select to remain active after the current transfer. In order to do so, he MUST acquire the bus first with `spi_device_acquire_bus()` function, else, an error is returned. --- components/driver/include/driver/spi_master.h | 8 +++-- components/driver/spi_master.c | 34 ++++++++++++++----- components/hal/esp32/include/hal/spi_ll.h | 10 ++++++ components/hal/esp32c3/include/hal/spi_ll.h | 10 ++++++ components/hal/esp32h2/include/hal/spi_ll.h | 10 ++++++ components/hal/esp32s2/include/hal/spi_ll.h | 10 ++++++ components/hal/esp32s3/include/hal/spi_ll.h | 10 ++++++ components/hal/include/hal/spi_hal.h | 1 + components/hal/spi_hal_iram.c | 3 ++ 9 files changed, 84 insertions(+), 12 deletions(-) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index da5f5b5214..8582a33276 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -105,7 +105,7 @@ typedef struct { #define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``. #define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Use the ``dummy_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``. #define SPI_TRANS_SET_CD (1<<7) ///< Set the CD pin - +#define SPI_TRANS_CS_KEEP_ACTIVE (1<<8) ///< Keep CS active after data transfer /** * This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes. */ @@ -194,7 +194,8 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle); * @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to * never time out. * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_DEVICE_CS_KEEP_LOW flag is specified while + * the bus was not acquired (`spi_device_acquire_bus()` should be called first) * - ESP_ERR_TIMEOUT if there was no room in the queue before ticks_to_wait expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished @@ -257,7 +258,8 @@ esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *tra * currently only portMAX_DELAY is supported. * * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_ARG if parameter is invalid. This can happen if SPI_DEVICE_CS_KEEP_LOW flag is specified while + * the bus was not acquired (`spi_device_acquire_bus()` should be called first) * - ESP_ERR_TIMEOUT if the device cannot get control of the bus before ``ticks_to_wait`` expired * - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed * - ESP_ERR_INVALID_STATE if previous transactions are not finished diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 84674f26df..5efe7993cd 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -466,14 +466,13 @@ int spi_get_actual_clock(int fapb, int hz, int duty_cycle) static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev) { spi_bus_lock_dev_handle_t dev_lock = dev->dev_lock; - - if (!spi_bus_lock_touch(dev_lock)) { - //if the configuration is already applied, skip the following. - return; - } spi_hal_context_t *hal = &dev->host->hal; spi_hal_dev_config_t *hal_dev = &(dev->hal_dev); - spi_hal_setup_device(hal, hal_dev); + + if (spi_bus_lock_touch(dev_lock)) { + /* Configuration has not been applied yet. */ + spi_hal_setup_device(hal, hal_dev); + } } static SPI_MASTER_ISR_ATTR spi_device_t *get_acquiring_dev(spi_host_t *host) @@ -512,12 +511,11 @@ static void spi_bus_intr_disable(void *host) // Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used) static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf) { - spi_transaction_t *trans = NULL; + spi_transaction_t *trans = trans_buf->trans; spi_host_t *host = dev->host; spi_hal_context_t *hal = &(host->hal); spi_hal_dev_config_t *hal_dev = &(dev->hal_dev); - trans = trans_buf->trans; host->cur_cs = dev->id; //Reconfigure according to device settings, the function only has effect when the dev_id is changed. @@ -531,6 +529,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_ hal_trans.send_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_send; hal_trans.cmd = trans->cmd; hal_trans.addr = trans->addr; + hal_trans.cs_keep_active = (trans->flags & SPI_TRANS_CS_KEEP_ACTIVE) ? 1 : 0; //Set up QIO/DIO if needed hal_trans.io_mode = (trans->flags & SPI_TRANS_MODE_DIO ? (trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_DIO : SPI_LL_IO_MODE_DUAL) : @@ -784,6 +783,12 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE ); + /* Even when using interrupt transfer, the CS can only be kept activated if the bus has been + * acquired with `spi_device_acquire_bus()` first. */ + if (host->device_acquiring_lock != handle && (trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE)) { + return ESP_ERR_INVALID_ARG; + } + spi_trans_priv_t trans_buf; ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled)); if (ret != ESP_OK) return ret; @@ -921,8 +926,16 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE ); + /* If device_acquiring_lock is set to handle, it means that the user has already + * acquired the bus thanks to the function `spi_device_acquire_bus()`. + * In that case, we don't need to take the lock again. */ if (host->device_acquiring_lock != handle) { - ret = spi_bus_lock_acquire_start(handle->dev_lock, ticks_to_wait); + /* The user cannot ask for the CS to keep active has the bus is not locked/acquired. */ + if ((trans_desc->flags & SPI_TRANS_CS_KEEP_ACTIVE) != 0) { + ret = ESP_ERR_INVALID_ARG; + } else { + ret = spi_bus_lock_acquire_start(handle->dev_lock, ticks_to_wait); + } } else { ret = spi_bus_lock_wait_bg_done(handle->dev_lock, ticks_to_wait); } @@ -963,6 +976,9 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_end(spi_device_handle_t handle, uninstall_priv_desc(&host->cur_trans_buf); host->polling = false; + /* Once again here, if device_acquiring_lock is set to `handle`, it means that the user has already + * acquired the bus thanks to the function `spi_device_acquire_bus()`. + * In that case, the lock must not be released now because . */ if (host->device_acquiring_lock != handle) { assert(host->device_acquiring_lock == NULL); spi_bus_lock_acquire_end(handle->dev_lock); diff --git a/components/hal/esp32/include/hal/spi_ll.h b/components/hal/esp32/include/hal/spi_ll.h index efd5170309..426d720843 100644 --- a/components/hal/esp32/include/hal/spi_ll.h +++ b/components/hal/esp32/include/hal/spi_ll.h @@ -496,6 +496,16 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) hw->pin.cs2_dis = (cs_id == 2) ? 0 : 1; } +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) { + hw->pin.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + /*------------------------------------------------------------------------------ * Configs: parameters *----------------------------------------------------------------------------*/ diff --git a/components/hal/esp32c3/include/hal/spi_ll.h b/components/hal/esp32c3/include/hal/spi_ll.h index cf773da678..8d2c1079f5 100644 --- a/components/hal/esp32c3/include/hal/spi_ll.h +++ b/components/hal/esp32c3/include/hal/spi_ll.h @@ -604,6 +604,16 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; } +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) { + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + /*------------------------------------------------------------------------------ * Configs: parameters *----------------------------------------------------------------------------*/ diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h index e4f462dc11..1f68acac7b 100644 --- a/components/hal/esp32h2/include/hal/spi_ll.h +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -603,6 +603,16 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; } +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) { + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + /*------------------------------------------------------------------------------ * Configs: parameters *----------------------------------------------------------------------------*/ diff --git a/components/hal/esp32s2/include/hal/spi_ll.h b/components/hal/esp32s2/include/hal/spi_ll.h index 16cf0b99eb..855036d05d 100644 --- a/components/hal/esp32s2/include/hal/spi_ll.h +++ b/components/hal/esp32s2/include/hal/spi_ll.h @@ -566,6 +566,16 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) hw->misc.cs5_dis = (cs_id == 5) ? 0 : 1; } +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) { + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + /*------------------------------------------------------------------------------ * Configs: parameters *----------------------------------------------------------------------------*/ diff --git a/components/hal/esp32s3/include/hal/spi_ll.h b/components/hal/esp32s3/include/hal/spi_ll.h index 8c85823b4e..1748105bff 100644 --- a/components/hal/esp32s3/include/hal/spi_ll.h +++ b/components/hal/esp32s3/include/hal/spi_ll.h @@ -612,6 +612,16 @@ static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id) } } +/** + * Keep Chip Select activated after the current transaction. + * + * @param hw Beginning address of the peripheral registers. + * @param keep_active if 0 don't keep CS activated, else keep CS activated + */ +static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active) { + hw->misc.cs_keep_active = (keep_active != 0) ? 1 : 0; +} + /*------------------------------------------------------------------------------ * Configs: parameters *----------------------------------------------------------------------------*/ diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index 1c4dc3a049..b37c7c9250 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -101,6 +101,7 @@ typedef struct { uint8_t *send_buffer; ///< Data to be sent uint8_t *rcv_buffer; ///< Buffer to hold the receive data. spi_ll_io_mode_t io_mode; ///< IO mode of the master + int cs_keep_active; ///< Keep CS active after transaction } spi_hal_trans_config_t; /** diff --git a/components/hal/spi_hal_iram.c b/components/hal/spi_hal_iram.c index 7c609b8e18..456fb942f5 100644 --- a/components/hal/spi_hal_iram.c +++ b/components/hal/spi_hal_iram.c @@ -131,6 +131,9 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev spi_ll_set_command(hw, trans->cmd, cmdlen, dev->tx_lsbfirst); spi_ll_set_address(hw, trans->addr, addrlen, dev->tx_lsbfirst); + //Configure keep active CS + spi_ll_master_keep_cs(hw, trans->cs_keep_active); + //Save the transaction attributes for internal usage. memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t)); }