mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-05 13:44:32 +02:00
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
This commit is contained in:
@@ -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_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_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_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.
|
* 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
|
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
|
||||||
* never time out.
|
* never time out.
|
||||||
* @return
|
* @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_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_NO_MEM if allocating DMA-capable temporary buffer failed
|
||||||
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
|
* - 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.
|
* currently only portMAX_DELAY is supported.
|
||||||
*
|
*
|
||||||
* @return
|
* @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_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_NO_MEM if allocating DMA-capable temporary buffer failed
|
||||||
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
|
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
|
||||||
|
@@ -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)
|
static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev)
|
||||||
{
|
{
|
||||||
spi_bus_lock_dev_handle_t dev_lock = dev->dev_lock;
|
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_context_t *hal = &dev->host->hal;
|
||||||
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
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)
|
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)
|
// 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)
|
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_host_t *host = dev->host;
|
||||||
spi_hal_context_t *hal = &(host->hal);
|
spi_hal_context_t *hal = &(host->hal);
|
||||||
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
|
||||||
|
|
||||||
trans = trans_buf->trans;
|
|
||||||
host->cur_cs = dev->id;
|
host->cur_cs = dev->id;
|
||||||
|
|
||||||
//Reconfigure according to device settings, the function only has effect when the dev_id is changed.
|
//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.send_buffer = (uint8_t*)host->cur_trans_buf.buffer_to_send;
|
||||||
hal_trans.cmd = trans->cmd;
|
hal_trans.cmd = trans->cmd;
|
||||||
hal_trans.addr = trans->addr;
|
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
|
//Set up QIO/DIO if needed
|
||||||
hal_trans.io_mode = (trans->flags & SPI_TRANS_MODE_DIO ?
|
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) :
|
(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 );
|
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;
|
spi_trans_priv_t trans_buf;
|
||||||
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
|
ret = setup_priv_desc(trans_desc, &trans_buf, (host->bus_attr->dma_enabled));
|
||||||
if (ret != ESP_OK) return ret;
|
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 );
|
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) {
|
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 {
|
} else {
|
||||||
ret = spi_bus_lock_wait_bg_done(handle->dev_lock, ticks_to_wait);
|
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);
|
uninstall_priv_desc(&host->cur_trans_buf);
|
||||||
|
|
||||||
host->polling = false;
|
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) {
|
if (host->device_acquiring_lock != handle) {
|
||||||
assert(host->device_acquiring_lock == NULL);
|
assert(host->device_acquiring_lock == NULL);
|
||||||
spi_bus_lock_acquire_end(handle->dev_lock);
|
spi_bus_lock_acquire_end(handle->dev_lock);
|
||||||
|
@@ -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;
|
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
|
* Configs: parameters
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
@@ -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;
|
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
|
* Configs: parameters
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
@@ -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;
|
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
|
* Configs: parameters
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
@@ -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;
|
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
|
* Configs: parameters
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
@@ -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
|
* Configs: parameters
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
@@ -101,6 +101,7 @@ typedef struct {
|
|||||||
uint8_t *send_buffer; ///< Data to be sent
|
uint8_t *send_buffer; ///< Data to be sent
|
||||||
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
|
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
|
||||||
spi_ll_io_mode_t io_mode; ///< IO mode of the master
|
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;
|
} spi_hal_trans_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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_command(hw, trans->cmd, cmdlen, dev->tx_lsbfirst);
|
||||||
spi_ll_set_address(hw, trans->addr, addrlen, 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.
|
//Save the transaction attributes for internal usage.
|
||||||
memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
|
memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user