The above code has several changes compared to the previous ones. With the option AdcHandler.Init.ScanConvMode = ADC_SCAN_ENABLE;
, the sequence in which the channels are converted no longer depends on their number, but can be assigned using sChanConfig.Rank = ADC_REGULAR_RANK_2;
, accepting values from 1 to 8; the lower the number, the earlier it will be converted. In this program, channel 9 is read first and then channel 8. It is necessary to indicate the number of ranks that will be used with the option AdcHandler.Init.NbrOfConversion = 2;
. Conversions are started by software using the function HAL_ADC_Start_IT
, but this function activates the interrupt each time a channel finishes a conversion (as stipulated in the option AdcHandler.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
). The callback function HAL_ADC_ConvCpltCallback
is called, and in it, the necessary logic must be implemented to read one channel first and then the other. Since the discontinuous conversion mode is not activated, the conversions of the two channels are performed sequentially with a single trigger (a single call to the HAL_ADC_Start_IT function
).
#include "bsp.h"
#include <stdio.h>
ADC_HandleTypeDef AdcHandler; /*adc handler estructure*/
ADC_ChannelConfTypeDef sChanConfig; /*adc channel configuration structure*/
uint32_t pot1, pot2, flag;
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 = ( 160.5 + 8.5 ) / 2MHz = 84.5us */
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_160CYCLES_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 );
/*config adc channel number 1*/
sChanConfig.Channel = ADC_CHANNEL_1;
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)
{
/*only print values until data from both channnel are ready*/
if( flag == 2u )
{
printf( "pot 1: %lu, pot 2: %lu\r\n", pot1, pot2 );
flag = 0u;
HAL_ADC_Start_IT( &AdcHandler ); /*iniciamos conversion del canal 8 y 9*/
}
HAL_Delay( 1000u );
}
}
/*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 )
{
/*we need to count the conversion in turn to differentiaite from channel 0 and 1*/
if( flag == 0u )
{
/*channel 0 first*/
pot1 = HAL_ADC_GetValue( hadc );
}
else
{
/*channel 1 later*/
pot2 = HAL_ADC_GetValue( hadc );
}
flag++;
}
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_PIN_1;
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 );
}