spi_slave: add valid check for DMA buffers

The DMA cannot receive data correctly when the buffer address is not
WORD aligned. Currently we only check whether the buffer is in the DRAM
region.

The DMA always write in WORDs, so the length arguments should also be
multiples of 32 bits.

A check is added to see whether the buffer is WORD aligned and has valid
length.
This commit is contained in:
michael
2018-11-20 11:13:44 +08:00
committed by bot
parent 435adaa22a
commit cfba157fdd
5 changed files with 40 additions and 20 deletions

View File

@@ -73,7 +73,10 @@ struct spi_slave_transaction_t {
size_t length; ///< Total data length, in bits
size_t trans_len; ///< Transaction data length, in bits
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase
void *rx_buffer; /**< Pointer to receive buffer, or NULL for no MISO phase.
* When the DMA is anabled, must start at WORD boundary (``rx_buffer%4==0``),
* and has length of a multiple of 4 bytes.
*/
void *user; ///< User-defined variable. Can be used to store eg transaction ID.
};

View File

@@ -298,8 +298,10 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
"rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL ||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
(trans_desc->length%4==0)),
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
r = xQueueSend(spihost[host]->trans_queue, (void *)&trans_desc, ticks_to_wait);

View File

@@ -78,12 +78,12 @@ static void slave_init()
TEST_ESP_OK( spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, 2) );
}
TEST_CASE("test slave startup","[spi]")
TEST_CASE("test slave send unaligned","[spi]")
{
uint8_t master_txbuf[320]=MASTER_SEND;
uint8_t master_rxbuf[320];
uint8_t slave_txbuf[320]=SLAVE_SEND;
uint8_t slave_rxbuf[320];
WORD_ALIGNED_ATTR uint8_t master_txbuf[320]=MASTER_SEND;
WORD_ALIGNED_ATTR uint8_t master_rxbuf[320];
WORD_ALIGNED_ATTR uint8_t slave_txbuf[320]=SLAVE_SEND;
WORD_ALIGNED_ATTR uint8_t slave_rxbuf[320];
spi_device_handle_t spi;
//initial master
@@ -97,13 +97,13 @@ TEST_CASE("test slave startup","[spi]")
int_connect( PIN_NUM_CS, HSPICS0_OUT_IDX, VSPICS0_IN_IDX );
int_connect( PIN_NUM_CLK, HSPICLK_OUT_IDX, VSPICLK_IN_IDX );
for ( int i = 0; i < 3; i ++ ) {
for ( int i = 0; i < 4; i ++ ) {
//slave send
spi_slave_transaction_t slave_t;
spi_slave_transaction_t* out;
memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
slave_t.length=8*32;
slave_t.tx_buffer=slave_txbuf+2*i;
slave_t.tx_buffer=slave_txbuf+i;
slave_t.rx_buffer=slave_rxbuf;
TEST_ESP_OK( spi_slave_queue_trans( VSPI_HOST, &slave_t, portMAX_DELAY ) );

View File

@@ -144,6 +144,11 @@ inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p)
return (intptr_t)p >= SOC_DMA_LOW && (intptr_t)p < SOC_DMA_HIGH;
}
inline static bool IRAM_ATTR esp_ptr_word_aligned(const void *p)
{
return ((intptr_t)p) % 4 == 0;
}
inline static bool IRAM_ATTR esp_ptr_executable(const void *p)
{
intptr_t ip = (intptr_t) p;

View File

@@ -85,6 +85,16 @@ Warning: Due to a design peculiarity in the ESP32, if the amount of bytes sent b
of the transmission queues in the slave driver, in bytes, is not both larger than eight and dividable by
four, the SPI hardware can fail to write the last one to seven bytes to the receive buffer.
Restrictions and Known issues
-------------------------------
1. If the DMA is enabled, the rx buffer should be WORD aligned, i.e. Start
from the boundary of 32-bit and have length of multiples of 4 bytes. Or the
DMA may write incorrectly or out of the boundary.The driver will check for
this.
Also, master should write lengths which are a multiple of 4 bytes. Data
longer than that will be discarded.
Application Example
-------------------