cancel
Showing results for 
Search instead for 
Did you mean: 

Problem when receiving data as a SPI slave from a SPI master using DMA

SKrey.1
Associate II

Hello,

Ive looped a datatransfer between STM32 SPI Master Port (on SPI3) to a slave port (on SPI2) on the same STM32 MCU. When I use DMA to send (from Master port) the data in blocks of 15 bytes, the data is not properly received on the SPI2 rx buffer (also DMA is used here to put the data from SPI2 fifo into a buffer). Only the first byte is received properly, then second byte is already wasted.

However in a logic analyzer I can see that the data properly appears on the MOSI line. However what I also see is that when using the DMA (compared non-DMA transfer) there is no space in between the bytes. Can this cause an issue in synchronization on the receiver site or anything? And if yes how to get things running then?

Here's my setup:

CPOL = 0, CPHAS = 0, baudrate = 80MHz / 8 = 10MHz, datawith = 8bits, FIFORx thresholds = 1byte (quarter full).

STM device is a STM32L451CE

Thanks for any help on this issue. If you need additional information, please let me know.

Kind Regards,

Steve

P.S. If I increase the Baudrate effects get more drastical, if I decrease the data is received much more stable. Also to mention is that I use cables to connect the ports on a Nucleos eval board.

7 REPLIES 7
TDK
Guru

You need to ensure the slave is ready before you start sending data. Since this is all on the same chip, you'll have to use nonblocking calls for the slave.

Hard to say what's wrong without any code.

If you feel a post has answered your question, please click "Accept as Solution".

What is exactly "wasted"?

Read out and post content of SPI registers.

What cable are you using? On the master side, try decreasing the SCK "drive" in GPIO_OSPEEDR. Do you interconnect NSS? If yes, how are you driving it?

Which board? Isn't some of the used pins connected to some onboard facility?

JW

SKrey.1
Associate II

Hello,

first of all thanks for the fast answer and sorry for beeing not so specific in my problem description. I try to be more specific now.

Please see attached screenshot of an SPI trace I captured just now. We see on the MOSI that the data is send as an incrementing counter starting @165 counting upwards. The second screenshot attached shows the internal buffer after receiption.

Now I have two problems on slave side:

1.) Slave-Rx: The data as you see in the variable "rx_data" in the 2nd screenshot is not fitting to the MOSI line shown in the trace screenshot (the first byte is correct, while the second which is actually 0xB3 should be 0xA6.

2.) Slave-Tx: The "tx_data" as visible in the screen is the same counter starting @0xA5, however in the screenshot we see that the data is not correctly shifted out on the MISO line.

Also please have a look at attachment registers.png to see the SPI registers after transmission (of 1024 bytes) is complete.

Following is the code how I setup TX/RX channel on the slave:

uint8_t tx_data[1024];
    uint8_t rx_data[1024];
    void Init(void)
    {
 
        LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
        //LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_5);
        //LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_5);
        LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_5, LL_SPI_DMA_GetRegAddr(SPI2));
        LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PERIPH_NOINCREMENT);
        LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MEMORY_INCREMENT);
        LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_5, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
        LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_5, LL_DMA_REQUEST_1);
 
        LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, LL_SPI_DMA_GetRegAddr(SPI2));
        LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
        LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
        LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
        LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_1);
 
        LL_GPIO_InitTypeDef GPIO_InitStruct;
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
 
 
        for (int i = 0; i < sizeof(tx_data); i++)
        {
            tx_data[i] = 0xA5 + i;
        }
 
        LL_GPIO_StructInit(&GPIO_InitStruct);
        //Serializer MISO/MOSI/SCLK
        GPIO_InitStruct.Pin = LL_GPIO_PIN_10 | LL_GPIO_PIN_11 | LL_GPIO_PIN_12;
        GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
        GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
        GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
        GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
        LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
        LL_GPIO_StructInit(&GPIO_InitStruct);
        //Slave MISO/MOSI
        GPIO_InitStruct.Pin = LL_GPIO_PIN_3 | LL_GPIO_PIN_2;
        GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
        GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
        GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
        GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
        LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
        LL_GPIO_StructInit(&GPIO_InitStruct);
        //Slave SS1/SCLK
        GPIO_InitStruct.Pin = LL_GPIO_PIN_13 | LL_GPIO_PIN_12;
        GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
        GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
        GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
        GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
        LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
        LL_SPI_InitTypeDef spiConfig;
        LL_SPI_StructInit(&spiConfig);
        spiConfig.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
        LL_SPI_Init(SPI2, &spiConfig);
        LL_SPI_Enable(SPI2);
        LL_SPI_SetRxFIFOThreshold(SPI2, LL_SPI_RX_FIFO_TH_QUARTER);
 
        LL_SPI_EnableDMAReq_TX(SPI2);
        LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_5);
        LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_5, (uint32_t) tx_data);
        LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_5, sizeof(tx_data));
        LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_5);
 
        LL_SPI_EnableDMAReq_RX(SPI2);
        LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
        LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) rx_data);
        LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, sizeof(rx_data));
        LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
	}

Thanks for your help in advance.

Kind regards,

Steve

SKrey.1
Associate II
 
SKrey.1
Associate II
 
SKrey.1
Associate II

Please also note that if I put a spacing (delay) in between the bytes on the MOSI (i.e. I dont send it using DMA on the master side), the data is properly received and transmitted back on the slave side. See attached screenshot as well. The problem only seems to occur if there's no (long enough) space in between the bytes being send on the MOSI line.

TDK
Guru

Looks like your slave signal sees an extra pulse during the second byte.

Can you take an analog capture with sufficient bandwidth?

Does the problem still occur if you slow down the clock but still use DMA?

0693W000003PztOQAS.png

If you feel a post has answered your question, please click "Accept as Solution".