cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F373 SDADC injected sequence using DMA drifts through the data buffer

RStep.6
Associate II

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

5 REPLIES 5
Piranha
Chief II

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
Associate II

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.

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

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
Chief II

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.