AnsweredAssumed Answered

STM32F7 DMA fails to write to SRAM

Question asked by Pabouctsidis.Alex on Apr 19, 2016
Latest reply on Apr 19, 2016 by gonzalez.laurent
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 the HAL_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

Outcomes