By default, the ADC converts all active channels in sequence, but it only has one data register to store one conversion result, so it overrides all channel results until the end of the sequence. To prevent this, interrupts can be utilized by setting AdcHandler.Init.EOCSelection
to trigger the interrupt at the end of a single conversion or at the end of the sequence. However, there is one drawback to this approach: the conversion time must be slow enough for the MCU to react and enter the interrupt, as demonstrated in the example where the conversion time is 21 microseconds
#include "app_bsp.h"
#include <stdio.h>
ADC_HandleTypeDef AdcHandler; /*adc handler estructure*/
ADC_ChannelConfTypeDef sChanConfig; /*adc channel configuration structure*/
uint32_t value;
extern void initialise_monitor_handles(void);
int main(void)
{
HAL_Init(); /*init HAL library*/
/*Enable semihosting only to display adc lecture*/
initialise_monitor_handles();
printf("Hola semihosting\n\r");
/* Conversion time is given by::
Tcon = ( Tsampling + Tconv ) / ADC clock
Tcon = ( AdcHandler.Init.SamplingTimeCommon1 + AdcHandler.Init.Resolution ) / ( APB Clock / AdcHandler.Init.ClockPrescaler )
Tcon = ( 1.5 + 8.5 ) / 8MHz = 1.25us */
AdcHandler.Instance = ADC1;
AdcHandler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; /*APB clock divided by two*/
AdcHandler.Init.Resolution = ADC_RESOLUTION8b; /*8 bit resolution with a Tconv of 8.5*/
AdcHandler.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED; /*scan adc channels from 0 to 16 in that order*/
AdcHandler.Init.DataAlign = ADC_DATAALIGN_RIGHT; /*data converter is right alightned*/
AdcHandler.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5; /*sampling time of 1.5*/
AdcHandler.Init.ExternalTrigConv = ADC_SOFTWARE_START; /*software trigger*/
AdcHandler.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /*ISR at the end of one channel conversion*/
AdcHandler.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /*data will be overwriten in case is not read it*/
/*apply ADC configuration*/
HAL_ADC_Init( &AdcHandler );
/*config adc channel number 0*/
sChanConfig.Channel = ADC_CHANNEL_0;
sChanConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sChanConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
/*apply channel configuration*/
HAL_ADC_ConfigChannel( &AdcHandler, &sChanConfig );
/*Apply internal calibration*/
HAL_ADCEx_Calibration_Start( &AdcHandler );
/*trigger conversion on channel 0 plus active interrupt*/
HAL_ADC_Start_IT( &AdcHandler );
while (1)
{
/*quey of a conversion is ready*/
if( value != 0u )
{
printf( "pot : %lu\r\n", value ); /*print the adc values*/
value = 0u;
HAL_ADC_Start_IT( &AdcHandler ); /*trigger conversion on channel 0 plus active interrupt*/
HAL_Delay( 1000u ); /*retardo de 1000ms*/
}
}
}
/*When conversion is ready this fucntion is called from HAL_ADC_IRQHandler
which is in turn called from the ADC1_COMP_IRQHandler interrupt vector*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
value = HAL_ADC_GetValue( hadc );
}
msps.c
/*This function is called in HAL_ADC_Init*/
void HAL_ADC_MspInit( ADC_HandleTypeDef* hadc )
{
GPIO_InitTypeDef GPIO_InitStruct;
__ADC_CLK_ENABLE(); /*enable adc clock*/
__GPIOA_CLK_ENABLE(); /*enable clock port where the adc 0 is connected*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; /*pin in analog mode*/
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*enable ADC vector interupt*/
HAL_NVIC_SetPriority( ADC1_COMP_IRQn, 2, 0 );
HAL_NVIC_EnableIRQ( ADC1_COMP_IRQn );
}
ints.c
/*reference to ADC control structure handler*/
extern ADC_HandleTypeDef AdcHandler;
/*Declare ADC interrupt service rutine as it is declare in startup_stm32g0b1xx.s file*/
void ADC1_COMP_IRQHandler( void )
{
/*HAL library functions that attend interrupt on ADC*/
HAL_ADC_IRQHandler( &AdcHandler );
}