cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F051 -> ADC1 -> sometimes no value returned....

jogerh
Associate II
Posted on June 07, 2015 at 11:43

Dear community,

I investigated the ADC_BasicExample given in the STM32F0xx_StdPeriph_Lib_V1.5.0 Database. I did a few changes since I want to analyze the converted value with the PC via UART. However I noticed if the EOC flag was cleared not necessarily the ADC returned a value. Is the interrupt better suited than the polling method given in the basic example ?

Here is some code for review:

//some functions to trigger the praser located on a remote pc 
int SendChar(char ch) //copied from USART example
{
// Place your implementation of fputc here 
// e.g. write a character to the USART 
USART_SendData(USART1, (uint8_t) ch);
// Loop until transmit data register is empty 
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 
return ch;
}
void print(char * string) {
char primer[] = ''print'';
int count;
//send primer
for(count = 0; count < 5; count++) SendChar(primer[count]); 
//now sen the string to print 
while(!(*string == '\0')) {
SendChar(*string); 
string++; 
}
SendChar(10); //now send the end of the string
}
void Send_value(int * value) {
char primer[] = ''value'';
int count;
//send primer
for(count = 0; count < 5; count++) SendChar(primer[count]);
//now send the char to the pc via uart
SendChar(*value);
}
//ADC1 Init
void ADC_Config(void) //copied from ADC_BasicExample
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// GPIOC Periph clock enable 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
// ADC1 Periph clock enable 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// Configure ADC Channel11 as analog input 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// ADCs DeInit 
ADC_DeInit(ADC1);
// Initialize ADC structure 
ADC_StructInit(&ADC_InitStructure);
// Configure the ADC1 in continuous mode with a resolution equal to 8 // 12 bits 
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;// ADC_Resolution_12b; //ADC_Resolution_8b;//ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure); 
// Convert the ADC1 Channel 11 with 5 Cycles as sampling time 
ADC_ChannelConfig(ADC1, ADC_Channel_11 , ADC_SampleTime_239_5Cycles);
// ADC_ChannelConfig(ADC1, ADC_Channel_10 , ADC_SampleTime_239_5Cycles);
// ADC Calibration 
ADC_GetCalibrationFactor(ADC1);
// Enable the ADC peripheral 
ADC_Cmd(ADC1, ENABLE); 
// Wait the ADRDY flag 
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
// ADC1 regular Software Start Conv 
ADC_StartOfConversion(ADC1);
}
void InitPeriphery() {
COM_USART1_Init();
ADC_Config();
}
int main(void) {
int received;
InitPeriphery();
while(1) { 
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
received = ADC_GetConversionValue(ADC1);
if(received) Send_value(&received ); // somtimes ADC_GetConversionValue was passed however access to ''received'' was somehow impossible 
print(''+ \0''); //waste some time to check the praser is working
print('' + \0'');
print('' + \0'');
print('' + \0'');
print('' + \0'');
print('' + \0'');
print('' + \0'');
};
}

I would be very if someone could check the code for mistakes- Thank you very much.
7 REPLIES 7
jogerh
Associate II
Posted on June 07, 2015 at 12:09

Dear community,

I searched the forum and found one of CLIVE1’s posts ->

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Do%20ADC_GetConversionValue%20read%20the%20current%20ADC%20value&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FF...

According to this post I changed a line in the ADC_config:

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //ENABLE;

Now my polling method is (hopefully) always returning a value (so far I can see it now)

while(1) {

ADC_StartOfConversion(ADC1);

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

received = ADC_GetConversionValue(ADC1);

if(received) Send_value(&received );

print(''WASTE SOME TIME\0'');

};

Posted on June 07, 2015 at 21:53

You might want to review how you send the value, and perhaps output it as an ASCII numeric, rather than output the low-order byte in a raw fashion.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on June 08, 2015 at 19:33

Thank you for responding to my post.

Do you know, why the ADC cannot be used in continues mode for polling although the polling- method waits until the EOC flag was reset?

Posted on June 08, 2015 at 20:16

Do you know, why the ADC cannot be used in continues mode for polling although the polling- method waits until the EOC flag was reset?

Well I suspect that in continuous mode you don't need to be starting every conversion, because that's happening automatically. And frankly 240 cycles is going to evaporate very quickly if you're faffing about with multiple characters out the USART.

Perhaps it's flagging an overrun or some other status condition you are ignoring?

Decide what you want to do. Initiate each conversion at a time you want, or have an endless stream you service promptly.

Most applications for multiple channels or continuous conversion use DMA to offload busy work from the processor. If pacing is important, use a timer to trigger the conversions.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on June 11, 2015 at 19:28

Hi,

I wasn’t aware whether the ADC can set an „overrun“ flag.

  *   This parameter can be one of the following values:

  *     @arg ADC_IT_EOC: End of conversion interrupt

  *     @arg ADC_IT_AWD: Analog watchdog interrupt

  *     @arg ADC_IT_JEOC: End of injected conversion interrupt

  *     @arg ADC_IT_OVR: overrun interrupt

Now I doubt that ADC_GetConversionValue(ADC1) takes itself to long for retrieving the converted value if the conversion is performed continuously.

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)

{

  /* Check the parameters */

  assert_param(IS_ADC_ALL_PERIPH(ADCx)); // perhaps this takes too long

  /* Return the selected ADC conversion value */

  return (uint16_t) ADCx->DR;

}

Posted on June 11, 2015 at 20:47

In your construct it's this that is the time waster,

                               if(received) Send_value(&received );

                              print(''WASTE SOME TIME\0'');           

Remember you told it to convert continuously, so the clock starts ticking again once EOC is raised and then you read the DR.

You don't specify a baud rate, but one can assume you're eating 1000's of cycles. Consider 9600 baud, less than 1000 characters per second, taking more than 1ms a piece. A processor running 24 MHz, so at least 24000 processor cycles per character.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on June 13, 2015 at 16:57

Thank you for the hint.

I checked the reference manual and found the following text on page 242. Now the problem is clear for me (hopefully).

The ADC sets the EOC flag in the ADC_ISR register as soon as a new conversion data result is available in the ADC_DR register. An interrupt can be generated if the EOCIE bit is set in the ADC_IER register.

The EOC flag is cleared by software either by writing 1 to it, or by reading the ADC_DR register.

The ADC also indicates the end of sampling phase by setting the EOSMP flag in the ADC_ISR register. The EOSMP flag is cleared by software by writing1 to it. An interrupt can be generated if the EOSMPIE bit is set in the ADC_IER register.

The aim of this interrupt is to allow the processing to be synchronized with the conversions. Typically, an analog multiplexer can be accessed in hidden time during the conversion phase, so that the multiplexer is positioned when the next sampling starts.

Note:As there is only a very short time left between the end of the sampling and the end of the conversion, it is recommenced to use polling or a WFE instruction rather than an interrupt and a WFI instruction.