Skip to main content
RStep.6
Associate
December 7, 2021
Question

STM32F373 SDADC injected sequence using DMA drifts through the data buffer

  • December 7, 2021
  • 3 replies
  • 5061 views

I am having trouble using the DMA with SDADC. The samples are coming in ok but their sequence in the buffer drifts through it. Anyone can help? i.e. every channel is open to the air except for one input i have a voltage applied. This value you can clearly see in the data buffer array is in index position 0, you wait and then the entire buffer shifts up by 1 position, it keeps doing this.

Code below:

DMA_InitTypeDef hdma_sdadcx;
	SDADC_InitTypeDef SDADC_InitStructure;
 SDADC_AINStructTypeDef SDADC_AINStructure;
 uint32_t SDADCTimeout = 0;
 
	/* DeInit SDADC */
 SDADC_DeInit(SDADC1);
 /* DeInit SDADC */
 SDADC_DeInit(SDADC2);
 /* DeInit SDADC */
 SDADC_DeInit(SDADC3);
	
 /* Select External reference: The reference voltage selection is available
 only in SDADC1 and therefore to select the VREF for SDADC2/SDADC3, SDADC1
 clock must be already enabled */
 SDADC_VREFSelect(SDADC_VREF_Ext);
 
	/* SDADC2 DMA Init */
	/* SDADC2 Init */
	hdma_sdadcx.DMA_BufferSize = 5;
	hdma_sdadcx.DMA_MemoryBaseAddr = (uint32_t)&sdADC2_Result;
	hdma_sdadcx.DMA_PeripheralBaseAddr = (uint32_t)&SDADC2->JDATAR;
	hdma_sdadcx.DMA_DIR = DMA_DIR_PeripheralSRC;
	hdma_sdadcx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	hdma_sdadcx.DMA_MemoryInc = DMA_MemoryInc_Enable;
	hdma_sdadcx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	hdma_sdadcx.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	hdma_sdadcx.DMA_Mode = DMA_Mode_Circular;
	hdma_sdadcx.DMA_Priority = DMA_Priority_High;
	DMA_Init(DMA2_Channel4,&hdma_sdadcx);	
	
	//Enable DMA control
	SDADC_DMAConfig(SDADC2,SDADC_DMATransfer_Injected, ENABLE);
	
	//SDADC_SlowClockCmd(SDADC1, ENABLE);
	SDADC_SlowClockCmd(SDADC2, ENABLE);
	SDADC_SlowClockCmd(SDADC3, ENABLE);
	
	/* Set channels to sample */
	SDADC_InjectedChannelSelect(SDADC2, SDADC_Channel_0 | SDADC_Channel_2 | SDADC_Channel_4 | SDADC_Channel_6 | SDADC_Channel_8);
 
	SDADC_ExternalTrigInjectedConvConfig(SDADC2, SDADC_CR2_JEXTSEL_0 | SDADC_CR2_JEXTSEL_1);
	SDADC_ExternalTrigInjectedConvEdgeConfig(SDADC2, SDADC_ExternalTrigInjecConvEdge_Rising);
	
	/* Enable SDADC */
 SDADC_Cmd(SDADC2, ENABLE);
 
	uint32_t t = 375000U;
 /* Insert delay equal to ~5 ms */
 while(t--)
	{
		__nop();
	}
	
	//////////////////////////////////////////////////////////////////////////////////////////////
 /* Enter initialization mode */
 SDADC_InitModeCmd(SDADC2, ENABLE);
 
 SDADCTimeout = SDADC_INIT_TIMEOUT;
 /* wait for INITRDY flag to be set */
 while((SDADC_GetFlagStatus(SDADC2, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
 
 if(SDADCTimeout == 0)
 {
 /* INITRDY flag can not set */
 }
 
 /* Analog Input configuration conf0:*/
 SDADC_AINStructure.SDADC_InputMode = SDADC_InputMode_Diff;
 SDADC_AINStructure.SDADC_Gain = SDADC_Gain_1;
 SDADC_AINStructure.SDADC_CommonMode = SDADC_CommonMode_VDDA_2;
 SDADC_AINStructure.SDADC_Offset = 0;
 SDADC_AINInit(SDADC2, SDADC_Conf_0, &SDADC_AINStructure);
 
 /* select SDADC channel to use conf0 */
 SDADC_ChannelConfig(SDADC2, SDADC_Channel_0, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC2, SDADC_Channel_2, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC2, SDADC_Channel_4, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC2, SDADC_Channel_6, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC2, SDADC_Channel_8, SDADC_Conf_0);
	
 /* Exit initialization mode */
 SDADC_InitModeCmd(SDADC2, DISABLE);
	//////////////////////////////////////////////////////////////////////////////////////////////
 
 /* configure calibration to be performed on conf0 */
 SDADC_CalibrationSequenceConfig(SDADC2, SDADC_CalibrationSequence_1);
 
	/* start SDADC Calibration */
 SDADC_StartCalibration(SDADC2);
 
 /* Set calibration timeout: 5.12 ms at 6 MHz in a single calibration sequence */
 SDADCTimeout = SDADC_CAL_TIMEOUT;
 
	/* wait for SDADC Calibration process to end */
 while((SDADC_GetFlagStatus(SDADC2, SDADC_FLAG_EOCAL) == RESET) && (--SDADCTimeout != 0));
 
 if(SDADCTimeout == 0)
 {
 /* EOCAL flag can not set */
 }
	
	 /* Enable continuous mode */
 //SDADC_InjectedContinuousModeCmd(SDADC2, ENABLE);
 
	//SDADC3 setup
	hdma_sdadcx.DMA_BufferSize = 3;
	hdma_sdadcx.DMA_MemoryBaseAddr = (uint32_t)&sdADC3_Result;
	hdma_sdadcx.DMA_PeripheralBaseAddr = (uint32_t)&SDADC3->JDATAR;
	hdma_sdadcx.DMA_DIR = DMA_DIR_PeripheralSRC;
	hdma_sdadcx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	hdma_sdadcx.DMA_MemoryInc = DMA_MemoryInc_Enable;
	hdma_sdadcx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	hdma_sdadcx.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	hdma_sdadcx.DMA_Mode = DMA_Mode_Circular;
	hdma_sdadcx.DMA_Priority = DMA_Priority_High;
	DMA_Init(DMA2_Channel5,&hdma_sdadcx);	
	
	//Enable DMA control
	SDADC_DMAConfig(SDADC3,SDADC_DMATransfer_Injected, ENABLE);
	
	/* Set channels to sample */
	SDADC_InjectedChannelSelect(SDADC3, SDADC_Channel_0 | SDADC_Channel_2 | SDADC_Channel_4);
	
	SDADC_ExternalTrigInjectedConvConfig(SDADC3, SDADC_CR2_JEXTSEL_0 | SDADC_CR2_JEXTSEL_1);
	SDADC_ExternalTrigInjectedConvEdgeConfig(SDADC3, SDADC_ExternalTrigInjecConvEdge_Falling);
		
	/* Enable SDADC */
 SDADC_Cmd(SDADC3, ENABLE);
	
	t = 375000U;
 /* Insert delay equal to ~5 ms */
 while(t--)
	{
		__nop();
	}
 
	//////////////////////////////////////////////////////////////////////////////////////////////
 /* Enter initialization mode */
 SDADC_InitModeCmd(SDADC3, ENABLE);
 
 SDADCTimeout = SDADC_INIT_TIMEOUT;
 /* wait for INITRDY flag to be set */
 while((SDADC_GetFlagStatus(SDADC3, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
 
 if(SDADCTimeout == 0)
 {
 /* INITRDY flag can not set */
 }
 
 /* Analog Input configuration conf0*/
 SDADC_AINStructure.SDADC_InputMode = SDADC_InputMode_Diff;
 SDADC_AINStructure.SDADC_Gain = SDADC_Gain_1;
 SDADC_AINStructure.SDADC_CommonMode = SDADC_CommonMode_VDDA_2;
 SDADC_AINStructure.SDADC_Offset = 0;
 SDADC_AINInit(SDADC3, SDADC_Conf_0, &SDADC_AINStructure);
 
 /* select SDADC channel to use conf0 */
 SDADC_ChannelConfig(SDADC3, SDADC_Channel_0, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC3, SDADC_Channel_2, SDADC_Conf_0);
	SDADC_ChannelConfig(SDADC3, SDADC_Channel_4, SDADC_Conf_0);
	
 /* Exit initialization mode */
 SDADC_InitModeCmd(SDADC3, DISABLE);
	//////////////////////////////////////////////////////////////////////////////////////////////
 
 /* configure calibration to be performed on conf0 */
 SDADC_CalibrationSequenceConfig(SDADC3, SDADC_CalibrationSequence_1);
 
	/* start SDADC Calibration */
 SDADC_StartCalibration(SDADC3);
 
 /* Set calibration timeout */
 SDADCTimeout = SDADC_CAL_TIMEOUT;
 
	/* wait for SDADC Calibration process to end */
 while((SDADC_GetFlagStatus(SDADC3, SDADC_FLAG_EOCAL) == RESET) && (--SDADCTimeout != 0));
 
 if(SDADCTimeout == 0)
 {
 /* EOCAL flag can not set */
 }
	
	 /* Enable continuous mode */
 //SDADC_InjectedContinuousModeCmd(SDADC3, ENABLE);
 
	DMA_Cmd(DMA2_Channel4, ENABLE);
	DMA_Cmd(DMA2_Channel5, ENABLE);
	
	SDADC_SoftwareStartInjectedConv(SDADC2);
	SDADC_SoftwareStartInjectedConv(SDADC3);

 Tried slowing down the SDADC, using slow clock 1.5Mhz, using Tim3 TRGO every 33ms to trigger the SDADC. Still doing it. I wonder if it is because of the DMA in circular mode so i set to normal, still experiencing the same thing.

Is it a bug? Could a member of ST comment please?

Thanks

This topic has been closed for replies.

3 replies

Piranha
Principal III
December 26, 2021

Because of some delay in your system, an ADC overrun happens. To deal with it, one must process the overrun interrupt and restart ADC and DMA from the start of the channel sequence.

RStep.6
RStep.6Author
Associate
February 8, 2022

Hi I have tried handling the flag clearing it in the interrupt but it does nothing to help. The data still drifts its position through the buffer.

Piranha
Principal III
February 10, 2022

My previous comment has more information than "clear it"...

RStep.6
RStep.6Author
Associate
February 11, 2022

Your answer said process the overrun and restart ADC and DMA. I cleared the overrun flag (dont know how else i can process it), disabled both ADC and DMA then re enabled them. Is this what you expect? It didnt seem to do anything sadly. Looking at the datasheet it also mentions the overrun flag has no affect on the SDADC sampling.

Piranha
Principal III
February 12, 2022

To restart the DMA from the beginning, you have to reinitialize the transfer counter. Therefore, when the DMA is disabled, you also have to reinitialize the DMA_CNDTRx register. In SPL it can be done by DMA_SetCurrDataCounter() function.