AnsweredAssumed Answered

STM32F4, SPI with DMA: strange behaviour

Question asked by kotev.kostadin on Aug 5, 2014
Latest reply on Aug 6, 2014 by kotev.kostadin
Hello ,

I have successfully implemented a quick and dirty communication between the STM32F407 and an external ADC ADS1278 via the SPI, using DMA. Everything seems to work fine until the moment I try to simplify/optimize my code.

I try to replace these lines of code:
01./* save measured value */
02.for(i = 0; i < ADC_CHANNEL_NUM; i++){
03.    extADCVoltage[i] = extADCChannelRawValues[i]*VOLTAGE_PER_VALUE;
04.}
05.         
06./* if calibration doen, then calculate value */ // do not know why it is not working with for loop
07.if(0 != calibrationParams[0][0]){
08.    extADCVoltage[0] = extADCVoltage[0]*calibrationParams[SLOPE_Idx][0] + calibrationParams[OFFSET_Idx][0];
09.    extADCVoltage[1] = extADCVoltage[1]*calibrationParams[SLOPE_Idx][1] + calibrationParams[OFFSET_Idx][1];
10.    extADCVoltage[2] = extADCVoltage[2]*calibrationParams[SLOPE_Idx][2] + calibrationParams[OFFSET_Idx][2];
11.    extADCVoltage[3] = extADCVoltage[3]*calibrationParams[SLOPE_Idx][3] + calibrationParams[OFFSET_Idx][3];
12.    extADCVoltage[4] = extADCVoltage[4]*calibrationParams[SLOPE_Idx][4] + calibrationParams[OFFSET_Idx][4];
13.    extADCVoltage[5] = extADCVoltage[5]*calibrationParams[SLOPE_Idx][5] + calibrationParams[OFFSET_Idx][5];
14.    extADCVoltage[6] = extADCVoltage[6]*calibrationParams[SLOPE_Idx][6] + calibrationParams[OFFSET_Idx][6];
15.    extADCVoltage[7] = extADCVoltage[7]*calibrationParams[SLOPE_Idx][7] + calibrationParams[OFFSET_Idx][7];
16.}

with these:

01./* save measured value */
02.for(i = 0; i < ADC_CHANNEL_NUM; i++){
03.    extADCVoltage[i] = extADCChannelRawValues[i]*VOLTAGE_PER_VALUE;
04.         
05.        /* if calibration doen, then calculate value */
06.    if(0 != calibrationParams[0][0]){
07.         extADCVoltage[i] = extADCVoltage[i]*calibrationParams[SLOPE_Idx][i] + calibrationParams[OFFSET_Idx][i];
08.        }
09. 
10.}

but then the DMA reads false data into the receive buffer. I can see the data with a logic analyzer and it seems exactly the same in both cases. The problem is the data in the DMA receive buffer is not correct (seems kind like a bit shifted). 

Here are variables declaration:

1.__IO uint8_t ExtAdcRxBuff[SPI1_RX_BUFF_SIZE];
2.uint32_t extADCDataAvailable = 0;
3.float extADCVoltage[ADC_CHANNEL_NUM];
4.float calibrationMeasVoltage[2][ADC_CHANNEL_NUM];
5.float calibrationParams[2][ADC_CHANNEL_NUM];
6. 
7.int32_t extADCChannelRawValues[ADC_CHANNEL_NUM];

1. Does anyone have a clue what could be the problem?

2. Could it be that the SPI clock is not correct/moves due to the change in code and the first high edge of the SCLK is not at the correct position after data ready signal goes high, so every time there is a change in code it does not read the bits correctly?

Here is the initialization:

001./**
002.    * @brief Initialize SPI1 for the external cMB
003.    * @param None  
004.    * @retval None
005.    */
006.void ADS1278_SPI1_Init(){
007.     
008.    SPI_InitTypeDef SPI_InitStructure;
009.     
010.    /* RCC init */
011.    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
012.     
013.    /* SPI1 initialization */
014.    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
015.    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
016.    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
017.    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
018.    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // APB2 / 8 = 10.5 MHz
019.    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
020.  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
021.  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
022.    SPI_Init(SPI1, &SPI_InitStructure);
023.}
024. 
025. 
026./**
027.    * @brief Initialize DMA for the SPI1 for ADS1278 ext. ADC
028.    * @param None
029.    * @param None
030.    */
031.void ADS1278_DMA_Init(void){
032.     
033.    DMA_InitTypeDef DMA_InitStructure;
034.    NVIC_InitTypeDef NVIC_InitStructure;
035.     
036.    /* Enable RCC clock */
037.    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
038.     
039.    /* Disable stream if it was in use */
040.    DMA_DeInit(DMA2_Stream0);
041.    while(RESET != DMA_GetCmdStatus(DMA2_Stream0));
042.     
043.    /* Initiliaze DMA2 Channel 3 Stream 0 */
044.    DMA_InitStructure.DMA_Channel = DMA_Channel_3;
045.    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
046.    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
047.    DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t) &(SPI1->DR);
048.    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) (ExtAdcRxBuff);
049.    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
050.    DMA_InitStructure.DMA_PeripheralInc = DMA_MemoryInc_Disable;
051.    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
052.    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
053.    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
054.    DMA_InitStructure.DMA_BufferSize = SPI1_RX_BUFF_SIZE;
055.    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
056.    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
057.    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
058.    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
059.    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
060.             
061.    /* Enable DMA transfer complete interrupt */   
062.    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
063.     
064.    /* Inialize NVIC for the DMA interrupt */
065.    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
066.    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
067.    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
068.    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
069.    NVIC_Init(&NVIC_InitStructure);
070.     
071.    /* Connect SPI and DMA2 */
072.    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
073.     
074.    //memset(ExtAdcRxBuff, 0 , sizeof(ExtAdcRxBuff));
075.}
076. 
077. 
078./**
079.    * @brief Synchronize both boards
080.    * @param numBoardsConnected number of cMB boards connected
081.    * @retval None
082.    */
083.void ADS1278_SyncBoards(uint16_t numBoardsConnected){
084.     
085.    /* Enable CLK for both boards */
086.    /* Enable timer, PWM CLK signal for both boards */
087.    TIM_Cmd(TIM1, ENABLE);
088.    /* Enable SPI1 */
089.    SPI_Cmd(SPI1, ENABLE); 
090.     
091.    /* Set NSYNC low and reset to high */
092.    GPIOA->BSRRH |= ADS1278_PIN_NSYNC;
093.    Delay_1us(1); // wait at least 1 CLK Period, in this case 1 Period is 95ns (CLK = 10.5 MHz)
094.    GPIOA->BSRRL |= ADS1278_PIN_NSYNC;
095.     
096.    /* Wait for first valid data from both boards*/
097.    if(2 == numBoardsConnected){
098.        while((GPIO_ReadInputDataBit(GPIOC, ADS1278_PIN_NDRDY_LOW)) && (GPIO_ReadInputDataBit(GPIOC, ADS1278_PIN_NDRDY_HIGH))){
099.            ;
100.        }
101.    }
102.     
103.    /* Set NSYNC low and reset it to high one more time */
104.    GPIOA->BSRRH |= ADS1278_PIN_NSYNC;
105.    Delay_1us(1); // wait at least 1 CLK Period, in this case 1 Period is 95ns (CLK = 10.5 MHz)
106.    GPIOA->BSRRL |= ADS1278_PIN_NSYNC;
107.     
108.    /* Enable DMA2 Channel 3 Stream 0 for the SPI1 RX */
109.    DMA_Cmd(DMA2_Stream0, ENABLE);
110.}


Thank you in advance!

Outcomes