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.
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.