drivers: spi: esp32xx: Fix word size issue
This commit fixes the word size configuration issue described in #54746 by considering the data frame size when trasmitting in case the configuration is applied. It also fixes an heap corruption problem when using SPI DMA with a buffer that is not multiple of 32 bits in lenght and GDMA instance in initialization. Signed-off-by: Lucas Tamborrino <lucas.tamborrino@espressif.com>
This commit is contained in:
parent
08d1b33d07
commit
b100ffb1df
2 changed files with 19 additions and 22 deletions
|
@ -70,29 +70,31 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
|
||||||
size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
|
size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
|
||||||
size_t max_buf_sz =
|
size_t max_buf_sz =
|
||||||
cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||||
chunk_len = MIN(chunk_len, max_buf_sz);
|
size_t transfer_len = data->word_size ? data->dfs : MIN(chunk_len, max_buf_sz);
|
||||||
size_t bit_len = chunk_len << 3;
|
size_t bit_len = transfer_len << 3;
|
||||||
uint8_t *rx_temp = NULL;
|
uint8_t *rx_temp = NULL;
|
||||||
uint8_t *tx_temp = NULL;
|
uint8_t *tx_temp = NULL;
|
||||||
|
uint8_t dma_len_tx = data->word_size ? data->dfs : ctx->tx_len;
|
||||||
|
uint8_t dma_len_rx = data->word_size ? data->dfs : ctx->rx_len;
|
||||||
|
|
||||||
if (cfg->dma_enabled) {
|
if (cfg->dma_enabled) {
|
||||||
/* bit_len needs to be at least one byte long when using DMA */
|
/* bit_len needs to be at least one byte long when using DMA */
|
||||||
bit_len = !bit_len ? 8 : bit_len;
|
bit_len = !bit_len ? 8 : bit_len;
|
||||||
if (ctx->tx_buf && !esp_ptr_dma_capable((uint32_t *)&ctx->tx_buf[0])) {
|
if (ctx->tx_buf && !esp_ptr_dma_capable((uint32_t *)&ctx->tx_buf[0])) {
|
||||||
tx_temp = k_malloc(ctx->tx_len);
|
tx_temp = k_malloc(dma_len_tx);
|
||||||
if (!tx_temp) {
|
if (!tx_temp) {
|
||||||
LOG_ERR("Error allocating temp buffer Tx");
|
LOG_ERR("Error allocating temp buffer Tx");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memcpy(tx_temp, &ctx->tx_buf[0], ctx->tx_len);
|
memcpy(tx_temp, &ctx->tx_buf[0], dma_len_tx);
|
||||||
}
|
}
|
||||||
if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) ||
|
if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) ||
|
||||||
((int)&ctx->rx_buf[0] % 4 != 0))) {
|
((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_tx % 4 != 0))) {
|
||||||
/* The rx buffer need to be length of
|
/* The rx buffer need to be length of
|
||||||
* multiples of 32 bits to avoid heap
|
* multiples of 32 bits to avoid heap
|
||||||
* corruption.
|
* corruption.
|
||||||
*/
|
*/
|
||||||
rx_temp = k_calloc(((ctx->rx_len << 3) + 31) / 8, sizeof(uint8_t));
|
rx_temp = k_calloc(((dma_len_rx << 3) + 31) / 8, sizeof(uint8_t));
|
||||||
if (!rx_temp) {
|
if (!rx_temp) {
|
||||||
LOG_ERR("Error allocating temp buffer Rx");
|
LOG_ERR("Error allocating temp buffer Rx");
|
||||||
k_free(tx_temp);
|
k_free(tx_temp);
|
||||||
|
@ -118,7 +120,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
|
||||||
|
|
||||||
/* send data */
|
/* send data */
|
||||||
spi_hal_user_start(hal);
|
spi_hal_user_start(hal);
|
||||||
spi_context_update_tx(&data->ctx, data->dfs, chunk_len);
|
spi_context_update_tx(&data->ctx, data->dfs, transfer_len/data->dfs);
|
||||||
|
|
||||||
while (!spi_hal_usr_is_done(hal)) {
|
while (!spi_hal_usr_is_done(hal)) {
|
||||||
/* nop */
|
/* nop */
|
||||||
|
@ -128,10 +130,10 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
|
||||||
spi_hal_fetch_result(hal);
|
spi_hal_fetch_result(hal);
|
||||||
|
|
||||||
if (rx_temp) {
|
if (rx_temp) {
|
||||||
memcpy(&ctx->rx_buf[0], rx_temp, chunk_len);
|
memcpy(&ctx->rx_buf[0], rx_temp, transfer_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_context_update_rx(&data->ctx, data->dfs, chunk_len);
|
spi_context_update_rx(&data->ctx, data->dfs, transfer_len/data->dfs);
|
||||||
|
|
||||||
k_free(tx_temp);
|
k_free(tx_temp);
|
||||||
k_free(rx_temp);
|
k_free(rx_temp);
|
||||||
|
@ -166,7 +168,7 @@ static int spi_esp32_init_dma(const struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOC_GDMA_SUPPORTED
|
#ifdef SOC_GDMA_SUPPORTED
|
||||||
gdma_hal_init(&data->hal_gdma, cfg->dma_host);
|
gdma_hal_init(&data->hal_gdma, 0);
|
||||||
gdma_ll_enable_clock(data->hal_gdma.dev, true);
|
gdma_ll_enable_clock(data->hal_gdma.dev, true);
|
||||||
gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
|
gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
|
||||||
gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
|
gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
|
||||||
|
@ -324,8 +326,6 @@ static int IRAM_ATTR spi_esp32_configure(const struct device *dev,
|
||||||
data->trans_config.line_mode.addr_lines = 1;
|
data->trans_config.line_mode.addr_lines = 1;
|
||||||
data->trans_config.line_mode.cmd_lines = 1;
|
data->trans_config.line_mode.cmd_lines = 1;
|
||||||
|
|
||||||
hal_dev->cs_setup = 1;
|
|
||||||
|
|
||||||
/* SPI mode */
|
/* SPI mode */
|
||||||
hal_dev->mode = 0;
|
hal_dev->mode = 0;
|
||||||
if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
|
if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
|
||||||
|
@ -351,18 +351,14 @@ static int IRAM_ATTR spi_esp32_configure(const struct device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t spi_esp32_get_frame_size(const struct spi_config *spi_cfg)
|
static inline uint8_t spi_esp32_get_frame_size(const struct device *dev,
|
||||||
|
const struct spi_config *spi_cfg)
|
||||||
{
|
{
|
||||||
uint8_t dfs = SPI_WORD_SIZE_GET(spi_cfg->operation);
|
struct spi_esp32_data *data = dev->data;
|
||||||
|
|
||||||
dfs /= 8;
|
data->word_size = SPI_WORD_SIZE_GET(spi_cfg->operation);
|
||||||
|
|
||||||
if ((dfs == 0) || (dfs > 4)) {
|
return data->word_size ? data->word_size >> 3 : 1;
|
||||||
LOG_WRN("Unsupported dfs, 1-byte size will be used");
|
|
||||||
dfs = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dfs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int transceive(const struct device *dev,
|
static int transceive(const struct device *dev,
|
||||||
|
@ -393,7 +389,7 @@ static int transceive(const struct device *dev,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->dfs = spi_esp32_get_frame_size(spi_cfg);
|
data->dfs = spi_esp32_get_frame_size(dev, spi_cfg);
|
||||||
|
|
||||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
|
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct spi_esp32_data {
|
||||||
int irq_line;
|
int irq_line;
|
||||||
lldesc_t dma_desc_tx;
|
lldesc_t dma_desc_tx;
|
||||||
lldesc_t dma_desc_rx;
|
lldesc_t dma_desc_rx;
|
||||||
|
uint8_t word_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_ */
|
#endif /* ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_ */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue