Search code examples
cstm32adc

STM32F030 ADC Sequence Conversion


I need to setup the internal adc of my stm32f030 in order to make it working in single conversion and scan mode. Because I can't use HAL library I need to implement the code at the register level. I need that every time a start is issued the adc does the conversion of tow channels in sequence.

Here the setup code of the adc;

uint8_t User_Adc_Init(void)
{
   
  GPIO_InitTypeDef gpioAdcInit;

  //EXTI_InitTypeDef EXTI_InitStructure;
  //NVIC_InitTypeDef NVIC_InitStructure;
  
  ADC_InitTypeDef adc1Init;
  
  
  //
  // GPIO settings
  //
  
  
  // 1) Enable clock for the peripheral port
  
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
  
  // 2) Ports initializzation 
  
  gpioAdcInit.GPIO_Pin = PORTB_MODE_AN_PINS;
  gpioAdcInit.GPIO_Mode = GPIO_Mode_AN;
  gpioAdcInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
  gpioAdcInit.GPIO_Speed = GPIO_Speed_Level_3;
  
  GPIO_Init(GPIOB, &gpioAdcInit);
  
  
  //  
  // ADC settings 
  //
  
  //RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div2); 
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
  
  ADC_ClockModeConfig(ADC1, ADC_ClockMode_AsynClk); 
  
  adc1Init.ADC_Resolution = ADC_Resolution_12b; 
  adc1Init.ADC_ContinuousConvMode = DISABLE;
  adc1Init.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; 
  adc1Init.ADC_DataAlign = ADC_DataAlign_Right;
  adc1Init.ADC_ScanDirection = ADC_ScanDirection_Upward; 
  
  ADC_Init(ADC1, &adc1Init);
  
  ADC_DiscModeCmd(ADC1, DISABLE); // Disable discontinuous mode  
  ADC_WaitModeCmd(ADC1, ENABLE); 
  
  // 3) Channels setup
  
  ADC_ChannelConfig(ADC1, ADC_Channel_8, ADC_SampleTime_71_5Cycles);  
  ADC_ChannelConfig(ADC1, ADC_Channel_9, ADC_SampleTime_71_5Cycles);  
   
  ADC_ClearFlag(ADC1, (ADC_FLAG_AWD|ADC_FLAG_EOC|ADC_FLAG_ADRDY|ADC_FLAG_EOSMP|ADC_FLAG_EOSEQ|ADC_FLAG_OVR));
  
  // Abilitazione reiterata con attesa flag di ready
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET)
      // Abilita ADC
      ADC_Cmd(ADC1, ENABLE);
  
  return TRUE; 
  
}

Here the code for sequence conversion;

uint8_t User_Adc_Single_Scan(adcUsrPar_t *sAdc)
{
  
  //
  // 1) Check if ADC is ready for a new conversion   
  //  
  
  if(Check_Flag(sAdc, ADC_FLAG_ADRDY) == ADC_OK)
  {
    
     // Reset of status register 
     ADC_ClearFlag(sAdc->adcInstance, (ADC_FLAG_AWD|ADC_FLAG_EOC|ADC_FLAG_ADRDY|ADC_FLAG_EOSMP|ADC_FLAG_EOSEQ|ADC_FLAG_OVR));
    
     // Start a new convertion 
     ADC_StartOfConversion(sAdc->adcInstance);
    
  }
  else
  {
    
    return ADC_ERROR;
    
  }      
  
  //      
  // 2) Check if there is any data ready to be read
  //    

  do
  {
    
      // Wait for the EoSMP flag to be set
     if(Check_Flag(sAdc, ADC_FLAG_EOSMP) == ADC_ERROR)
        return ADC_ERROR; 
       
     // Wait for the EOC flag to be set 
     if(Check_Flag(sAdc, ADC_FLAG_EOC) == ADC_ERROR)
        return ADC_ERROR; 
     
    // Read new data available 
    sAdc->rawDataBus[sAdc->currentChIndex] = ADC_GetConversionValue(sAdc->adcInstance);
    
    // Increase index counter 
    sAdc->currentChIndex++;  

  }while(sAdc->currentChIndex < sAdc->numberOfChannels);    // !ADC_GetFlagStatus(sAdc->adcInstance, ADC_FLAG_EOSEQ));

  // Reset of the channel index
  sAdc->currentChIndex = 0;  

  //
  // 3) Check if the sequence of channels conversion is compleated 
  //
  
  // Clear of the EOSEQ flag
  ADC_ClearFlag(sAdc->adcInstance, ADC_FLAG_EOSEQ);
  
  // Toggle of SCANDIR
  sAdc->adcInstance->CFGR1 ^= ADC_CFGR1_SCANDIR;
    
  
  return ADC_OK; 

}

The problem is that after the first conversion EOS flag turns up and subsequent attempts lead to an error.

I didn't find any documentation well explainded about the low level configuration of this adc, and I can't figure out where is the error.


Solution

  • After many tries, I found that the error was in the following line of code;

         // Reset of status register 
         ADC_ClearFlag(sAdc->adcInstance, (ADC_FLAG_AWD|ADC_FLAG_EOC|ADC_FLAG_ADRDY|ADC_FLAG_EOSMP|ADC_FLAG_EOSEQ|ADC_FLAG_OVR));
    

    Clearing the flag "ADREADY" causes the ADC to stop any further convertion, which is not what we want.