Skip to main content
Visitor II
July 17, 2017
Question

STM32F091 SPI DMA Problem

  • July 17, 2017
  • 2 replies
  • 2191 views
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] << 8) | RxBuffer[0]); // / 16384.0f;

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

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

        DMA_ClearFlag(DMA1_FLAG_TC2);

    }

}

#stm32 #accelerometer #dma #spi
    This topic has been closed for replies.

    2 replies

    Super User
    July 17, 2017
    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

    Visitor II
    July 17, 2017
    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)

    Visitor II
    July 18, 2017
    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.

    Super User
    July 18, 2017
    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