STM32F051 -> ADC1 -> sometimes no value returned....
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-07 02:43 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-07 03:09 AM
Dear community,
I searched the forum and found one of CLIVE1’s posts ->
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'');
};
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-07 12:53 PM
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.
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-08 10:33 AM
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-08 11:16 AM
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.Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-11 10:28 AM
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;
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-11 11:47 AM
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.Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-06-13 07:57 AM
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.