Merge branch 'feature/spi_keep_cs_low' into 'master'

SPI: chip select can now be kept active if the bus has been acquired

Closes IDF-3125

See merge request espressif/esp-idf!13546
pull/6951/merge
Omar Chebib 2021-07-22 03:57:58 +00:00
commit 74d939fd71
9 zmienionych plików z 84 dodań i 12 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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
*----------------------------------------------------------------------------*/

Wyświetl plik

@ -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
*----------------------------------------------------------------------------*/

Wyświetl plik

@ -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
*----------------------------------------------------------------------------*/

Wyświetl plik

@ -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
*----------------------------------------------------------------------------*/

Wyświetl plik

@ -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
*----------------------------------------------------------------------------*/

Wyświetl plik

@ -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;
/**

Wyświetl plik

@ -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));
}