cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4, SPI with DMA: strange behaviour

kostadin
Associate II
Posted on August 05, 2014 at 10:31

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:


/* save measured value */

for
(i = 0; i < ADC_CHANNEL_NUM; i++){

extADCVoltage[i] = extADCChannelRawValues[i]*VOLTAGE_PER_VALUE;

}


/* if calibration doen, then calculate value */
// do not know why it is not working with for loop

if
(0 != calibrationParams[0][0]){

extADCVoltage[0] = extADCVoltage[0]*calibrationParams[SLOPE_Idx][0] + calibrationParams[OFFSET_Idx][0];

extADCVoltage[1] = extADCVoltage[1]*calibrationParams[SLOPE_Idx][1] + calibrationParams[OFFSET_Idx][1];

extADCVoltage[2] = extADCVoltage[2]*calibrationParams[SLOPE_Idx][2] + calibrationParams[OFFSET_Idx][2];

extADCVoltage[3] = extADCVoltage[3]*calibrationParams[SLOPE_Idx][3] + calibrationParams[OFFSET_Idx][3];

extADCVoltage[4] = extADCVoltage[4]*calibrationParams[SLOPE_Idx][4] + calibrationParams[OFFSET_Idx][4];

extADCVoltage[5] = extADCVoltage[5]*calibrationParams[SLOPE_Idx][5] + calibrationParams[OFFSET_Idx][5];

extADCVoltage[6] = extADCVoltage[6]*calibrationParams[SLOPE_Idx][6] + calibrationParams[OFFSET_Idx][6];

extADCVoltage[7] = extADCVoltage[7]*calibrationParams[SLOPE_Idx][7] + calibrationParams[OFFSET_Idx][7];

}

with these:


/* save measured value */

for
(i = 0; i < ADC_CHANNEL_NUM; i++){

extADCVoltage[i] = extADCChannelRawValues[i]*VOLTAGE_PER_VALUE;


/* if calibration doen, then calculate value */

if
(0 != calibrationParams[0][0]){

extADCVoltage[i] = extADCVoltage[i]*calibrationParams[SLOPE_Idx][i] + calibrationParams[OFFSET_Idx][i];

}


}

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:


/**

* @brief Initialize SPI1 for the external cMB

* @param None 

* @retval None

*/

void
ADS1278_SPI1_Init(){


SPI_InitTypeDef SPI_InitStructure;


/* RCC init */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);


/* SPI1 initialization */

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; 
// APB2 / 8 = 5 MHz

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;

SPI_Init(SPI1, &SPI_InitStructure);

}



/**

* @brief Initialize DMA for the SPI1 for ADS1278 ext. ADC

* @param None

* @param None

*/

void
ADS1278_DMA_Init(
void
){


DMA_InitTypeDef DMA_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;


/* Enable RCC clock */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);


/* Disable stream if it was in use */

DMA_DeInit(DMA2_Stream0);

while
(RESET != DMA_GetCmdStatus(DMA2_Stream0));


/* Initiliaze DMA2 Channel 3 Stream 0 */

DMA_InitStructure.DMA_Channel = DMA_Channel_3;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

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

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) (ExtAdcRxBuff);

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_PeripheralInc = DMA_MemoryInc_Disable;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_BufferSize = SPI1_RX_BUFF_SIZE;

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMA_Init(DMA2_Stream0, &DMA_InitStructure);


/* Enable DMA transfer complete interrupt */

DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);


/* Inialize NVIC for the DMA interrupt */

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);


/* Connect SPI and DMA2 */

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);


//memset(ExtAdcRxBuff, 0 , sizeof(ExtAdcRxBuff));

}



/**

* @brief Synchronize both boards 

* @param numBoardsConnected number of cMB boards connected

* @retval None

*/

void
ADS1278_SyncBoards(uint16_t numBoardsConnected){


/* Enable CLK for both boards */

/* Enable timer, PWM CLK signal for both boards */

TIM_Cmd(TIM1, ENABLE);

/* Enable SPI1 */

SPI_Cmd(SPI1, ENABLE); 


/* Set NSYNC low and reset to high */

GPIOA->BSRRH |= ADS1278_PIN_NSYNC;

Delay_1us(1); 
// wait at least 1 CLK Period, in this case 1 Period is 95ns (CLK = 5 MHz)

GPIOA->BSRRL |= ADS1278_PIN_NSYNC;


/* Wait for first valid data from both boards*/

if
(2 == numBoardsConnected){

while
((GPIO_ReadInputDataBit(GPIOC, ADS1278_PIN_NDRDY_LOW)) && (GPIO_ReadInputDataBit(GPIOC, ADS1278_PIN_NDRDY_HIGH))){

;

}

}


/* Set NSYNC low and reset it to high one more time */

GPIOA->BSRRH |= ADS1278_PIN_NSYNC;

Delay_1us(1); 
// wait at least 1 CLK Period, in this case 1 Period is 95ns (CLK = 5 MHz)

GPIOA->BSRRL |= ADS1278_PIN_NSYNC;


/* Enable DMA2 Channel 3 Stream 0 for the SPI1 RX */

DMA_Cmd(DMA2_Stream0, ENABLE);

}

Thank you in advance! #stm32f4 #spi #error #dma
2 REPLIES 2
Posted on August 05, 2014 at 13:26

DMA_InitStructure.DMA_PeripheralInc = DMA_MemoryInc_Disable;

//??

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kostadin
Associate II
Posted on August 06, 2014 at 04:48

Thanks, didn't see that. However, both of the Disable variables (Memory and Peripheral) are declared as 0-s, so it didn't make any difference: still receiving false data, when trying to use for the for loop. Any other ideas?