cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F091 SPI DMA Problem

Clemens Ehm
Associate II
Posted on July 17, 2017 at 16:25

Hello,

I try to read acceleration values from a LIS3DSHTR using the STM32F091 �C. I use SPI with DMA to read the values but I have trouble with the incoming datas in the RxBuffer.

On my two screenshots you can see the bus communication and the position of the data inside my RxBuffer. The order is totally wrong.

I hope someone can check the source code. I hope you can find a stupid mistake

void SPI_init()

{

    SPI_InitTypeDef SPI_InitStructure;

    // clk

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;

    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    // set af mode

    GPIOA->MODER = ( GPIOA->MODER & ~(GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7));

    GPIOA->MODER |= ( GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1);

    GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR5)) | (0 << GPIO_AFR_POS5);

    GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR6)) | (0 << GPIO_AFR_POS6);

    GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRL_AFR7)) | (0 << GPIO_AFR_POS7);

    SPIx_PORT->MODER |= ( GPIO_MODER_MODER4_0);

    SPIx_PORT->OTYPER &= ~( GPIO_OTYPER_OT_4);

    SPIx_PORT->OSPEEDR |= ( GPIO_OSPEEDER_OSPEEDR4);

    SPIx_PORT->PUPDR &= ~( GPIO_PUPDR_PUPDR4);

    SPIx_PORT->BSRR = GPIO_BSRR_BS_4; //High - Deselect ACC

    /*SPI1-Konfigurieren*/

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

    SPI_InitStructure.SPI_CRCPolynomial = 7;

    SPI_Init(SPIx,&SPI_InitStructure);

    //Use DMA for SPI

    SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);

    SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);

    SPI_Cmd(SPIx, ENABLE);

    //Init DMA

    DMA_Config();

    //Init the buffer with the needed registers of the acc

    AccelerationRequest[0] = ACCELEROMETER_OUT_X_L;

    AccelerationRequest[1] = 0x00; //dummy

    AccelerationRequest[2] = ACCELEROMETER_OUT_X_H;

    AccelerationRequest[3] = 0x00;

    AccelerationRequest[4] = ACCELEROMETER_OUT_Y_L;

    AccelerationRequest[5] = 0x00;

    AccelerationRequest[6] = ACCELEROMETER_OUT_Y_H;

    AccelerationRequest[7] = 0x00;

    AccelerationRequest[8] = ACCELEROMETER_OUT_Z_L;

    AccelerationRequest[9] = 0x00;

    AccelerationRequest[10] = ACCELEROMETER_OUT_Z_H;

    AccelerationRequest[11] = 0x00;

}

void DMA_Config()

{

    DMA_InitTypeDef DMA_InitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;

    DMA_DeInit(DMA1_Channel2);

    DMA_DeInit(DMA1_Channel3);

    DMA_StructInit(&DMA_InitStructure);

    // Enable DMA1 Peripheral Clock (SPI_DECAWAVE and SPI_BUS)

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // Configure SPI_BUS RX Channel

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // From SPI to memory

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_BufferSize = sizeof(RxBuffer);

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel2, &DMA_InitStructure);

    // Configure SPI_BUS TX Channel

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // From memory to SPI

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_BufferSize = sizeof(TxBuffer);;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel3, &DMA_InitStructure);

    DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}

//ReadAddrBuffer = AccelerationRequest with the Register values + DummyByte, Size = 12

void SPI_ReadRegisters(uint8_t* ReadAddrBuffer, uint8_t Size)

{

    for (uint8_t i=0; i < Size; i++)

    {

        if (ReadAddrBuffer[i] > 0x00)

            TxBuffer[i] = ReadAddrBuffer[i] | READ_FLAG;

        else

            TxBuffer[i] = 0x00;

    }

    DMA_Cmd(DMA1_Channel2, DISABLE);

    DMA_Cmd(DMA1_Channel3, DISABLE);

    DMA_SetCurrDataCounter(DMA1_Channel2, Size);

    DMA_SetCurrDataCounter(DMA1_Channel3, Size);

    SPI_SelectChip();

    DMA_Cmd(DMA1_Channel2, ENABLE);

    DMA_Cmd(DMA1_Channel3, ENABLE);

}

void DMA1_Channel2_3_IRQHandler(void)

{

    if (DMA_GetITStatus(DMA1_IT_TC2) != RESET)

    {

        SPI_DeselectChip();

        int16_t x = (int16_t)((RxBuffer[1] << 😎 | RxBuffer[0]); // / 16384.0f;

        int16_t y = (int16_t)((RxBuffer[3] << 😎 | RxBuffer[2]); // / 16384.0f;

        int16_t z = (int16_t)((RxBuffer[5] << 😎 | RxBuffer[4]); // / 16384.0f;

        DMA_ClearFlag(DMA1_FLAG_TC2);

    }

}

#stm32 #accelerometer #dma #spi
7 REPLIES 7
Posted on July 17, 2017 at 17:02

RxFIFO artefact, together with RXNE not being clear at the moment ?

Try tp test for RXNE and read DR accordingly, before enabling SPI/DMA; and perhaps change RxFIFO level to single byte. The data packing feature might get into way too.

The behaviour of 'advanced' SPI is not very clearly described in the RMs and might require some experimentation.

JW

Posted on July 17, 2017 at 20:49

Hello!

what type is RxBuffer  ?  Is it an array? 

in case  RxBuffer  is a pointer, sizeof(RxBuffer) gives  result 4.(32bit). (You have 4 bytes transaction)

Posted on July 18, 2017 at 09:11

uint8_t RxBuffer[12];

So the value of DMA_BufferSize should be 1, cause it must be equal with the MemoryDataSize and PeripheralDataSize.

Posted on July 18, 2017 at 10:21

No. It's the number of transactions, it is stored into DMA's NDTR register.

 uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Stream.

                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize

                                        or DMA_MemoryDataSize members depending in the transfer direction. */

Once again, read the SPI section thoroughly, focus on FIFO and data packing.

In program, check if RXNE is set before enabling SPI/DMA and read out any outstanding data.

JW

Posted on July 18, 2017 at 16:45

Thx for your help. Problem solved

Posted on July 18, 2017 at 17:09

How?

Posted on July 18, 2017 at 17:46

Before I enable SPI DMA and try to read data I'm doing this:

    if (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == SET)

    {

        uint8_t dummy = SPI1->DR;

    }

I dont enter this functions every time but sometimes - it obv helps - I have more trouble without it.

I had also another problem with my write only function to configure the accelerometer. The µC set the ChipSelect to High while the data transfer was still in progress. But I fixed this issue with checking the SPI Flags SPI_I2S_FLAG_BSY and SPI_I2S_FLAG_TXE.

And ofc changed the DMA_BufferSize and not using sizeof(RxBuffer).