mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 20:54:32 +02:00
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:
@@ -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.
|
||||
};
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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 ) );
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
-------------------
|
||||
|
Reference in New Issue
Block a user