mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(spi_master): add new feature allow use variable command and address field length for the same device.
Closes #654
This commit is contained in:
parent
7c9b24b407
commit
0330ec270a
@ -44,8 +44,8 @@ typedef void(*transaction_cb_t)(spi_transaction_t *trans);
|
||||
* @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t command_bits; ///< Amount of bits in command phase (0-16)
|
||||
uint8_t address_bits; ///< Amount of bits in address phase (0-64)
|
||||
uint8_t command_bits; ///< Default amount of bits in command phase (0-16), used when ``SPI_TRANS_VARIABLE_CMD`` is not used, otherwise ignored.
|
||||
uint8_t address_bits; ///< Default amount of bits in address phase (0-64), used when ``SPI_TRANS_VARIABLE_ADDR`` is not used, otherwise ignored.
|
||||
uint8_t dummy_bits; ///< Amount of dummy bits to insert between address and data phase
|
||||
uint8_t mode; ///< SPI mode (0-3)
|
||||
uint8_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.
|
||||
@ -65,6 +65,8 @@ typedef struct {
|
||||
#define SPI_TRANS_MODE_DIOQIO_ADDR (1<<4) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO
|
||||
#define SPI_TRANS_USE_RXDATA (1<<2) ///< Receive into rx_data member of spi_transaction_t instead into memory at rx_buffer.
|
||||
#define SPI_TRANS_USE_TXDATA (1<<3) ///< Transmit tx_data member of spi_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this.
|
||||
#define SPI_TRANS_VARIABLE_CMD (1<<4) ///< Use the ``command_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_VARIABLE_ADDR (1<<5) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
|
||||
/**
|
||||
* This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes.
|
||||
@ -90,6 +92,16 @@ struct spi_transaction_t {
|
||||
};
|
||||
} ; //the rx data should start from a 32-bit aligned address to get around dma issue.
|
||||
|
||||
/**
|
||||
* This struct is for SPI transactions which may change their address and command length.
|
||||
* Please do set the flags in base to ``SPI_TRANS_VARIABLE_CMD_ADR`` to use the bit length here.
|
||||
*/
|
||||
typedef struct {
|
||||
struct spi_transaction_t base; ///< Transaction data, so that pointer to spi_transaction_t can be converted into spi_transaction_ext_t
|
||||
uint8_t command_bits; ///< The command length in this transaction, in bits.
|
||||
uint8_t address_bits; ///< The address length in this transaction, in bits.
|
||||
} spi_transaction_ext_t ;
|
||||
|
||||
|
||||
typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus
|
||||
|
||||
|
@ -489,13 +489,9 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
|
||||
}
|
||||
|
||||
//Configure bit sizes, load addr and command
|
||||
//configure dummy bits
|
||||
host->hw->user.usr_dummy=(dev->cfg.dummy_bits+extra_dummy)?1:0;
|
||||
host->hw->user.usr_addr=(dev->cfg.address_bits)?1:0;
|
||||
host->hw->user.usr_command=(dev->cfg.command_bits)?1:0;
|
||||
host->hw->user1.usr_addr_bitlen=dev->cfg.address_bits-1;
|
||||
host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits+extra_dummy-1;
|
||||
host->hw->user2.usr_command_bitlen=dev->cfg.command_bits-1;
|
||||
//Configure misc stuff
|
||||
host->hw->user.doutdin=(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;
|
||||
host->hw->user.sio=(dev->cfg.flags & SPI_DEVICE_3WIRE)?1:0;
|
||||
@ -587,17 +583,36 @@ static void IRAM_ATTR spi_intr(void *arg)
|
||||
host->hw->miso_dlen.usr_miso_dbitlen=trans->length-1;
|
||||
}
|
||||
|
||||
//Configure bit sizes, load addr and command
|
||||
int cmdlen;
|
||||
if ( trans->flags & SPI_TRANS_VARIABLE_CMD ) {
|
||||
cmdlen = ((spi_transaction_ext_t*)trans)->command_bits;
|
||||
} else {
|
||||
cmdlen = dev->cfg.command_bits;
|
||||
}
|
||||
int addrlen;
|
||||
if ( trans->flags & SPI_TRANS_VARIABLE_ADDR ) {
|
||||
addrlen = ((spi_transaction_ext_t*)trans)->address_bits;
|
||||
} else {
|
||||
addrlen = dev->cfg.address_bits;
|
||||
}
|
||||
host->hw->user1.usr_addr_bitlen=addrlen-1;
|
||||
host->hw->user2.usr_command_bitlen=cmdlen-1;
|
||||
host->hw->user.usr_addr=addrlen?1:0;
|
||||
host->hw->user.usr_command=cmdlen?1:0;
|
||||
|
||||
// output command will be sent from bit 7 to 0 of command_value, and then bit 15 to 8 of the same register field.
|
||||
uint16_t command = trans->cmd << (16-dev->cfg.command_bits); //shift to MSB
|
||||
uint16_t command = trans->cmd << (16-cmdlen); //shift to MSB
|
||||
host->hw->user2.usr_command_value = (command>>8)|(command<<8); //swap the first and second byte
|
||||
// shift the address to MSB of addr (and maybe slv_wr_status) register.
|
||||
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
|
||||
if (dev->cfg.address_bits>32) {
|
||||
host->hw->addr = trans->addr >> (dev->cfg.address_bits - 32);
|
||||
host->hw->slv_wr_status = trans->addr << (64 - dev->cfg.address_bits);
|
||||
if (addrlen>32) {
|
||||
host->hw->addr = trans->addr >> (addrlen- 32);
|
||||
host->hw->slv_wr_status = trans->addr << (64 - addrlen);
|
||||
} else {
|
||||
host->hw->addr = trans->addr << (32 - dev->cfg.address_bits);
|
||||
host->hw->addr = trans->addr << (32 - addrlen);
|
||||
}
|
||||
|
||||
host->hw->user.usr_mosi=( (!(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX) && trans_buf->buffer_to_rcv) || trans_buf->buffer_to_send)?1:0;
|
||||
host->hw->user.usr_miso=(trans_buf->buffer_to_rcv)?1:0;
|
||||
|
||||
@ -645,6 +660,7 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
}
|
||||
if ( trans_buf.buffer_to_rcv && handle->host->dma_chan && (!esp_ptr_dma_capable( trans_buf.buffer_to_rcv ) || ((int)trans_buf.buffer_to_rcv%4!=0)) ) {
|
||||
//if rxbuf in the desc not DMA-capable, malloc a new one. The rx buffer need to be length of multiples of 32 bits to avoid heap corruption.
|
||||
ESP_LOGV( SPI_TAG, "Allocate RX buffer for DMA" );
|
||||
trans_buf.buffer_to_rcv = heap_caps_malloc((trans_desc->rxlength+31)/8, MALLOC_CAP_DMA);
|
||||
if ( trans_buf.buffer_to_rcv==NULL ) return ESP_ERR_NO_MEM;
|
||||
}
|
||||
@ -659,6 +675,7 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
|
||||
}
|
||||
if ( txdata && handle->host->dma_chan && !esp_ptr_dma_capable( txdata )) {
|
||||
//if txbuf in the desc not DMA-capable, malloc a new one
|
||||
ESP_LOGV( SPI_TAG, "Allocate TX buffer for DMA" );
|
||||
trans_buf.buffer_to_send = heap_caps_malloc((trans_desc->length+7)/8, MALLOC_CAP_DMA);
|
||||
if ( trans_buf.buffer_to_send==NULL ) {
|
||||
// free malloc-ed buffer (if needed) before return.
|
||||
|
@ -59,7 +59,7 @@ A transaction on the SPI bus consists of five phases, any of which may be skippe
|
||||
|
||||
In full duplex, the read and write phases are combined, causing the SPI host to read and
|
||||
write data simultaneously. The total transaction length is decided by
|
||||
``dev_conf.command_bits + dev_conf.address_bits + trans_conf.length``, while the ``trans_conf.rx_length``
|
||||
``command_bits + address_bits + trans_conf.length``, while the ``trans_conf.rx_length``
|
||||
only determins length of data received into the buffer.
|
||||
|
||||
In half duplex, the length of write phase and read phase are decided by ``trans_conf.length`` and
|
||||
@ -103,9 +103,25 @@ Using the spi_master driver
|
||||
- Optional: to remove the driver for a bus, make sure no more drivers are attached and call
|
||||
``spi_bus_free``.
|
||||
|
||||
Command and address phases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Transaction data
|
||||
^^^^^^^^^^^^^^^^
|
||||
During the command and address phases, ``cmd`` and ``addr`` field in the
|
||||
``spi_transaction_t`` struct are sent to the bus, while nothing is read at the
|
||||
same time. The default length of command and address phase are set in the
|
||||
``spi_device_interface_config_t`` and by ``spi_bus_add_device``. When the the
|
||||
flag ``SPI_TRANS_VARIABLE_CMD`` and ``SPI_TRANS_VARIABLE_ADDR`` are not set in
|
||||
the ``spi_transaction_t``,the driver automatically set the length of these
|
||||
phases to the default value as set when the device is initialized respectively.
|
||||
|
||||
If the length of command and address phases needs to be variable, declare a
|
||||
``spi_transaction_ext_t`` descriptor, set the flag ``SPI_TRANS_VARIABLE_CMD``
|
||||
or/and ``SPI_TRANS_VARIABLE_ADDR`` in the ``flags`` of ``base`` member and
|
||||
configure the rest part of ``base`` as usual. Then the length of each phases
|
||||
will be ``command_bits`` and ``address_bits`` set in the ``spi_transaction_ext_t``.
|
||||
|
||||
Write and read phases
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Normally, data to be transferred to or from a device will be read from or written to a chunk of memory
|
||||
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure.
|
||||
|
Loading…
Reference in New Issue
Block a user