Merge branch 'feature/spi_little_endien' into 'master'

feature(spi): provide macro to write multi-byte data straightly

See merge request idf/esp-idf!2634
This commit is contained in:
Angus Gratton 2018-07-03 14:32:41 +08:00
commit 52f4ff6220
3 changed files with 89 additions and 35 deletions

View file

@ -31,6 +31,34 @@ extern "C"
//Maximum amount of bytes that can be put in one DMA descriptor
#define SPI_MAX_DMA_LEN (4096-4)
/**
* Transform unsigned integer of length <= 32 bits to the format which can be
* sent by the SPI driver directly.
*
* E.g. to send 9 bits of data, you can:
*
* uint16_t data = SPI_SWAP_DATA_TX(0x145, 9);
*
* Then points tx_buffer to ``&data``.
*
* @param data Data to be sent, can be uint8_t, uint16_t or uint32_t. @param
* len Length of data to be sent, since the SPI peripheral sends from the MSB,
* this helps to shift the data to the MSB.
*/
#define SPI_SWAP_DATA_TX(data, len) __builtin_bswap32((uint32_t)data<<(32-len))
/**
* Transform received data of length <= 32 bits to the format of an unsigned integer.
*
* E.g. to transform the data of 15 bits placed in a 4-byte array to integer:
*
* uint16_t data = SPI_SWAP_DATA_RX(*(uint32_t*)t->rx_data, 15);
*
* @param data Data to be rearranged, can be uint8_t, uint16_t or uint32_t.
* @param len Length of data received, since the SPI peripheral writes from
* the MSB, this helps to shift the data to the LSB.
*/
#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
/**
* @brief Enum with the three SPI peripherals that are software-accessible in it

View file

@ -727,9 +727,12 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
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-cmdlen); //shift to MSB
host->hw->user2.usr_command_value = (command>>8)|(command<<8); //swap the first and second byte
/* Output command will be sent from bit 7 to 0 of command_value, and
* then bit 15 to 8 of the same register field. Shift and swap to send
* more straightly.
*/
host->hw->user2.usr_command_value = SPI_SWAP_DATA_TX(trans->cmd, cmdlen);
// 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 (addrlen>32) {

View file

@ -167,6 +167,10 @@ memcpy of temporary buffers.
.. note:: Half duplex transactions with both read and write phases are not supported when using DMA. See
:ref:`spi_known_issues` for details and workarounds.
Tips
""""
1. Transactions with small amount of data:
Sometimes, the amount of data is very small making it less than optimal allocating a separate buffer
for it. If the data to be transferred is 32 bits or less, it can be stored in the transaction struct
itself. For transmitted data, use the ``tx_data`` member for this and set the ``SPI_USE_TXDATA`` flag
@ -174,6 +178,25 @@ on the transmission. For received data, use ``rx_data`` and set ``SPI_USE_RXDATA
not touch the ``tx_buffer`` or ``rx_buffer`` members, because they use the same memory locations
as ``tx_data`` and ``rx_data``.
2. Transactions with integers other than uint8_t
The SPI peripheral reads and writes the memory byte-by-byte. By default,
the SPI works at MSB first mode, each bytes are sent or received from the
MSB to the LSB. However, if you want to send data with length which is
not multiples of 8 bits, unused bits are sent.
E.g. you write ``uint8_t data = 0x15`` (00010101B), and set length to
only 5 bits, the sent data is ``00010B`` rather than expected ``10101B``.
Moreover, ESP32 is a little-endian chip whose lowest byte is stored at
the very beginning address for uint16_t and uint32_t variables. Hence if
a uint16_t is stored in the memory, it's bit 7 is first sent, then bit 6
to 0, then comes its bit 15 to bit 8.
To send data other than uint8_t arrays, macros ``SPI_SWAP_DATA_TX`` is
provided to shift your data to the MSB and swap the MSB to the lowest
address; while ``SPI_SWAP_DATA_RX`` can be used to swap received data
from the MSB to it's correct place.
Speed and Timing Considerations
-------------------------------