2017-04-06 03:22 AM
Hi
I am trying to use the ADC in the STM32L07 as a multichannel scan. I have set up Cube for 3 analogue channels, AN0, Temperature and VRef Int. I have set it up for single scan usign the HAL_ADC_Start_IT(&hadc); command. Within the interupt routine I am checking the ADC_FLAG_EOC for after each channel completed, and the ADC_FLAG_EOS for after the complete scan is completed. When the HAL_ADC_Start_IT is called, I see the first channel with ADC_FLAG_EOC, but straight away the ADC_FLAG_EOS is also called. I am new to the chip, and not sure what I am doing wrong, can anyone advice me? My code is below, and attached is snap shot of the cube setting
Many Thanks
Scott
unsigned ADC_Raw[3];
unsigned char ADC_index=0; #define AD_VCCINT 2 #define AD_TEMP 1void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{ if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) { ADC_Raw[ADC_index++]=HAL_ADC_GetValue(hadc); ADC_raw = HAL_ADC_GetValue(hadc); } if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) { <<gets called straight after first conversion... ADC_index=0; Vdd = 3000 * (*VREFINT_CAL_ADDR)/ADC_Raw[AD_VCCINT]; temperature=(((int32_t)ADC_Raw[AD_TEMP]*Vdd/3000)-(int32_t)*TEMP30_CAL_ADDR); temperature*=(int32_t)(130-30); temperature/=(int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR); temperature+=30; } }static void MX_ADC_Init(void)
{ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/ hadc.Instance = ADC1; hadc.Init.OversamplingMode = DISABLE; hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.EOCSelection = ADC_EOC_SINGLE_SEQ_CONV; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerFrequencyMode = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; if (HAL_ADC_Init(&hadc) != HAL_OK) { Error_Handler(); }/**Configure for the selected ADC regular channel to be converted.
*/ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); }/**Configure for the selected ADC regular channel to be converted.
*/ sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); }/**Configure for the selected ADC regular channel to be converted.
*/ sConfig.Channel = ADC_CHANNEL_VREFINT; if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { Error_Handler(); }}
Note: this post was migrated and contained many threaded conversations, some content may be missing.2017-06-12 03:19 AM
Hey Scott
Thanks for the response, yeah this is pretty much what I ended up doing as well. I got notified that this has been reported as a bug so I hope it gets fixed soon.
Nathan
2017-06-26 07:22 AM
Hi Scott
STM are reporting this is fixed in 4.20, and im using 4.21 and still having issues.
Specifically, ADC_EOC_SINGLE_SEQ_CONV is still being generated from CubeMX. What is worse, is that cubeMX still allows you to select 'End of single or sequence of conversion' in the ADC parameters.
Scott, what version are you using?
2017-06-26 08:03 AM
On top of this, I have attempted your approached to use
ADC_EOC_SINGLE_CONV and to call
HAL_ADC_Start_IT within
HAL_ADC_ConvCpltCallback and it works, but only for 3 channels and I have 6. The other ADC channels values remain 0. Playing around with the debugger and to my surprise 5 of the 6 channels in the array managed to get data, but not the 6th. Tired playing around with debugger again and i still only to get 3 channels with data.
2017-06-27 04:17 AM
Hi,
'End of single or sequence of conversion' value for 'End Of Conversion Selection' parameter will be removed in coming release of CubeMX.So, the 'End Of Conversion Selection' parameter will be with the following possible values: - End of Single conversion - End of sequence of conversionRegardsImen2017-07-27 10:42 AM
You need to use discontinuous mode. Using other modes, the channels all get read very quickly and EOS bit gets set. You need to use interrupts to catch them before they get overwritten. By using discontinuous mode, you can start ADC and wait for completion, then read one channel. Only EOC bit will be set. Next pass, read next channel, etc. When you have read all channels, EOS bit will be set.
Marv
2017-07-29 02:20 AM
Hi
Sorry for taking so long in getting back to you, I have been away for a good while, and recently got back. I updated to the latest version, and cant remember what version I was running. Have you now solved the issue?
Scott
2017-07-30 01:08 PM
Yes, all running. Thanks.
Marv
Marvin D. Thorell, P.E.
Creative Engineering, LLC
3716 Sheridan Road
Racine, WI 53403
mdthorell@gmail.com
2017-07-30 07:53 PM
Yes
Using the latest HAL and CubeMX versions:
// Variables:
unsigned int ADC_raw[6];
unsigned char index1 = 0;
unsigned short int ADC_Busy = 0;
// ConvCpltCallback function as follows:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
ADC_Busy = 1;
if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))
{
ADC_raw[index1] = HAL_ADC_GetValue(hadc);
index1++;
}
if (index1 > 5)
{
index1 = 0;
ADC_Busy = 0;
}
}
// infinite loop:
while (1)
{
if(ADC_Busy == 0)
{
ADC_Busy = 1;
HAL_ADC_Start_IT(&hadc);
}
}
The key thing to know is to make sure you slow down the ADC clock so that when the interrupt
ConvCpltCallback
is called it has time to process. Also using variable index does not work, so I had to change to index12017-12-28 07:35 AM
,
,
Hello,
, , As @Marvin Thorell said, you should use discontinuous mode. , ADC hardware is fast and interrupt software rutines are pretty slow, you will miss some channels even if you increase the 'Sampling Time'. , So you need to stop ADC sampling for the next channel, check below code. But i offer you to use DMA transfer.
/* USER CODE BEGIN 0 */
,
int ADC_index,,
uint32_t ADC_Raw[3],,
,,
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc),
{,
, , ,if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)),
, , ,{,
, , , , , ,ADC_Raw[ADC_index++] = HAL_ADC_GetValue(hadc),,
, , , , , ,hadc->,Instance->,CR |= (uint32_t)ADC_CR_ADSTART,,
, , ,},
, , ,if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)),
, , ,{,
, , , , , ,if (ADC_index != 3),
, , , , , ,{,
, , , , , , , , ,/* Something is wrong! We may receive overrun error */,
, , , , , , , , ,__asm volatile('bkpt ♯ 0\n'),,
, , , , , ,},
, , , , , ,ADC_index = 0,,
, , ,},
},
,,
void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc),
{,
, , , if (HAL_ADC_GetError(hadc) &, HAL_ADC_ERROR_OVR),
, , , , , ,__asm volatile('bkpt ♯ 0\n'),,
},
,,
/* USER CODE END 0 */,
,,
int main(void),
{,
,,
, /* USER CODE BEGIN 1 */,
,,
, /* USER CODE END 1 */,
,,
, /* MCU Configuration----------------------------------------------------------*/,
,,
, /* Reset of all peripherals, Initializes the Flash interface and the Systick. */,
, HAL_Init(),,
,,
, /* USER CODE BEGIN Init */,
,,
, /* USER CODE END Init */,
,,
, /* Configure the system clock */,
, SystemClock_Config(),,
,,
, /* USER CODE BEGIN SysInit */,
,,
, /* USER CODE END SysInit */,
,,
, /* Initialize all configured peripherals */,
, MX_GPIO_Init(),,
, MX_ADC_Init(),,
,,
, /* USER CODE BEGIN 2 */,
,,
, /* USER CODE END 2 */,
,,
, /* Infinite loop */,
, /* USER CODE BEGIN WHILE */,
, ADC_index = 0,,
, HAL_ADC_Start_IT(&,hadc),,
, while (1),
, {,
, /* USER CODE END WHILE */,
,,
, /* USER CODE BEGIN 3 */,
,,
, },
, /* USER CODE END 3 */,
,,
},
,,
,,
/* ADC init function */,
static void MX_ADC_Init(void),
{,
,,
, ADC_ChannelConfTypeDef sConfig,,
,,
, , , /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) ,,
, , , */,
, hadc.Instance = ADC1,,
, hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1,,
, hadc.Init.Resolution = ADC_RESOLUTION_12B,,
, hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT,,
, hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD,,
, hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV,,
, hadc.Init.LowPowerAutoWait = DISABLE,,
, hadc.Init.LowPowerAutoPowerOff = DISABLE,,
, hadc.Init.ContinuousConvMode = DISABLE,,
, hadc.Init.DiscontinuousConvMode = ENABLE,,
, hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START,,
, hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE,,
, hadc.Init.DMAContinuousRequests = DISABLE,,
, hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED,,
, if (HAL_ADC_Init(&,hadc) != HAL_OK),
, {,
, , , _Error_Handler(__FILE__, __LINE__),,
, },
,,
, , , /**Configure for the selected ADC regular channel to be converted. ,,
, , , */,
, sConfig.Channel = ADC_CHANNEL_0,,
, sConfig.Rank = ADC_RANK_CHANNEL_NUMBER,,
, sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5,,
, if (HAL_ADC_ConfigChannel(&,hadc, &,sConfig) != HAL_OK),
, {,
, , , _Error_Handler(__FILE__, __LINE__),,
, },
,,
, , , /**Configure for the selected ADC regular channel to be converted. ,,
, , , */,
, sConfig.Channel = ADC_CHANNEL_TEMPSENSOR,,
, if (HAL_ADC_ConfigChannel(&,hadc, &,sConfig) != HAL_OK),
, {,
, , , _Error_Handler(__FILE__, __LINE__),,
, },
,,
, , , /**Configure for the selected ADC regular channel to be converted. ,,
, , , */,
, sConfig.Channel = ADC_CHANNEL_VREFINT,,
, if (HAL_ADC_ConfigChannel(&,hadc, &,sConfig) != HAL_OK),
, {,
, , , _Error_Handler(__FILE__, __LINE__),,
, },
,,
}