2016-04-19 06:05 AM
We've ran into a very strange DMA issue recently as we have been expanding our code. We noticed this problem after adding some new libraries which use up a lot of ram, which caused our existing spi+dma drivers stop working correctly (even though the new code was completely independent, and never executed!)
After a couple days of investigating i'm able to determine reproduce the condition of this problem, but am still baffled as to why its occuring. The problem is that our SPI+DMA transfers no longer works when the RX/TX buffer are located in the SRAM instead of the DTCMRAM. In order to highlight this issue, I've implemented the following test code: - I changed the linker script so that all of the code is placed in the SRAM, but with a CCRAM ram section declaration/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20010000, LENGTH = 240k
CCMRAM (rw) : ORIGIN = 0x20000000, LENGTH = 64K
}
- I have a test task which periodically reads a register value on our sensor using the SPI bus. The TX/RX buffers are global variables, and i can change their ram location using the ''__attribute__((section(''.ccmram'')))'' attribute.
//uint8_t tx_buffer[10] __attribute__((section(''.ccmram''))) = {0};
//uint8_t rx_buffer[10] __attribute__((section(''.ccmram''))) = {0};
uint8_t tx_buffer[10];
uint8_t rx_buffer[10];
void test_task(void *pvParameters)
{
tx_buffer[0] = SPI_CMD_PROM_READ | SPI_PROM_RESERVED;
vTaskDelay(1000);
while(1)
{
memset(rx_buffer,0xAB,10);
spi_ms5611_send(tx_buffer, rx_buffer, 3, RXTX, portMAX_DELAY);
vTaskDelay(1);
}
}
- The spi function is defined as:
uint8_t spi_ms5611_send(uint8_t* tx_buffer, uint8_t* rx_buffer,
uint32_t n_bytes, spi_direction_t direction, uint32_t timeout)
{
uint8_t return_flag = 1;
// Enable chip select
HAL_GPIO_WritePin(SPI_BARO_CSN_PORT, SPI_BARO_CSN_PIN, GPIO_PIN_RESET);
// Start spi transfer using appropriate hal function
switch(direction)
{
case TX:
HAL_SPI_Transmit_DMA(&g_hspi_baro, tx_buffer, n_bytes);
break;
case RX:
HAL_SPI_Receive_DMA(&g_hspi_baro, rx_buffer, n_bytes);
break;
case RXTX:
HAL_SPI_TransmitReceive_DMA(&g_hspi_baro, tx_buffer, rx_buffer, n_bytes);
break;
}
// Wait for Transmit to complete
return_flag = xSemaphoreTake(g_spi_baro_rx_dma_semaphore, timeout);
// Release chip select
HAL_GPIO_WritePin(SPI_BARO_CSN_PORT, SPI_BARO_CSN_PIN, GPIO_PIN_SET);
return return_flag;
}
We are using FreeRTOS and the send function blocks on a semaphore. the semaphore is released in theHAL_SPI_TxRxCpltCallback.
Observations:
- When the Tx/Rx buffers are placed in the DTCMRAM (0x20000000) everything works as it should. However, if i remove the __attribute(..), placing the buffers in the SRAM (0x20010000), the code executes completely (the dma callbacks are called, etc). but the RX buffer is never written to.
- RX buffer is filled with 0xAB before performing the spi transaction, and the values do not change. this shows that the DMA is not writing the values to the memory.
- I've compared both cases using an oscilloscope, and the spi lines are identical in both cases. The MOSI/MISO/CLK/CSN lines are active and contain the proper data.
- If i use the ''HAL_SPI_TransmitReceive'' (which uses interrupts) instead of ''HAL_SPI_TransmitReceive_DMA'', it works in both cases.
- I've played with the SPI clock, as well as the overall system clocks, to no effect.
I found nothing in the datasheet, reference manual, or errata sheet which would indicate why i am having this issue. Everything indicated
We desperately need some feedback in order to solve this issue.
Thanks,
Alex Pabouctsidis
2016-04-19 06:30 AM
SRAM is accessed through AXI, and is likely to be cached.
Do you have an ''MPU_Config'' function in your project that set the region cached ? So either avoid to use that region for DMA, or manage cache invalidation/flush by yourself, or run with no caches at all (beware the loss of performance).