STM32L0 ADC Problem converting multiple channels using DMA - c

I'm trying to convert 3 ADC channels using DMA. But the variables don't seem to change when I watch them in the debugger. I know the conversion complete callback is executed because I breakpointed it. So this suggests that the DMA transfer is not executing and the buffer is not being filled. I'm using stm32cube to initialize my project. I've trimmed the generated code. Thanks.
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;
uint32_t uwADC8ConvertedValue = 0;
uint32_t uwADC10ConvertedValue = 0;
uint32_t uwADC11ConvertedValue = 0;
uint32_t adcBuffer[3];
/* USER CODE BEGIN 0 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle) {
uwADC8ConvertedValue = adcBuffer[0];
uwADC10ConvertedValue = adcBuffer[1];
uwADC11ConvertedValue = adcBuffer[2];
}
/* USER CODE END 0 */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_RTC_Init();
MX_ADC_Init();
MX_USART2_UART_Init();
MX_USART5_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_ADC_Start_IT(&hadc);
HAL_ADC_Start_DMA(&hadc, adcBuffer, 3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Transmit(&huart2, TxBuffer, 15, 5000);
GPIO_PinState userPBstate = OFF;
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(MODEM_PW_GPIO_Port, MODEM_PW_Pin);
HAL_GPIO_TogglePin(CAM1_LD_GPIO_Port, CAM1_LD_Pin);
HAL_GPIO_TogglePin(CAM1_PW_GPIO_Port, CAM1_PW_Pin);
HAL_Delay(100);
userPBstate = HAL_GPIO_ReadPin(USER_PB_GPIO_Port, USER_PB_Pin);
if (userPBstate == ON) {
HAL_UART_Transmit(&huart2, (uint8_t *)"User button pressed!\n\r", 22, 5000);
}
else {
HAL_UART_Transmit(&huart2, (uint8_t *)"User button NOT pressed!\n\r", 26, 5000);
}
}
/* 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.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = ENABLE;
hadc.Init.EOCSelection = ADC_EOC_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(__FILE__, __LINE__);
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
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_10;
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_11;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

User custom code:
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_ADC_Start_IT(&hadc);
HAL_ADC_Start_DMA(&hadc, adcBuffer, 3);
/* USER CODE END 2 */
should be:
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_ADC_Start_DMA(&hadc, adcBuffer, 3);
/* USER CODE END 2 */
If you want to use DMA mode, then do not use interrupt mode.

Related

Not getting correct values of potentiometer in the channel1 and channel2 in stm32f103

I have been trying to read values from two potentiometers connected to channel1 and channel2 in ADC1 and read the values through UART in a serial Terminal,but unable to do it. It either comes random value or a same value for both the POTS. ADC works perfectly for a single channel.
The board I am using is STM32F103(Bluepill).
I have my own UART library that I am using to read.
ADC initialisation
in the regular channel configurations, I made two different functions of both thechannels
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
//ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
For configuring the regular channels I made two different functions as these will be called in other functions with a multiplication factor.
void ADC_SET_CH1()
{
//MX_ADC1_Init();
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_NVIC_EnableIRQ(ADC1_IRQn);
}
void ADC_SET_CH2()
{
//MX_ADC1_Init();
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_NVIC_EnableIRQ(ADC1_IRQn);
}
The different functions that I made in order to call them in the while loop to read the values in serial terminal:
float read_value1()
{
ADC_SET_CH1();
//rawData=0.1525*readAdc(0x01);
// HAL_ADC_Start_IT(&hadc1);
rawdata1=0.1525*HAL_ADC_GetValue(&hadc1);
return rawdata1;
}
float read_value2()
{
ADC_SET_CH2();
//rawData1=0.1525*readAdc(0x02);
//HAL_ADC_Start_IT(&hadc1);
rawData=0.1525*HAL_ADC_GetValue(&hadc1);
return rawData;
}
MAIN:
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "uart.h"
#include "stm32f1xx_it.h"
char *readbuffer;
float rawData=0.0f;
float potValue=0.0f;
char *readbuffer1;
float rawdata1=0.0f;
float potvalue1=0.0f;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc1);
while 1:
while (1)
{
potValue=read_value1();
readbuffer=(convertIntToString(potValue));
writeString1("pot0:");
writeString1(readbuffer);
//writeString1("\n");
HAL_Delay(500);
writeString1(" ");
potvalue1= read_value2();
readbuffer1=convertIntToString(potvalue1);
writeString1("pot1:");
writeString1(readbuffer1);
writeString1("\n");
}
}
The IRQ function:
void ADC1_2_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_2_IRQn 0 */
adcValue=ADC1->DR;
//HAL_ADC_Start_IT(&hadc1);
/* USER CODE END ADC1_2_IRQn 0 */
HAL_ADC_IRQHandler(&hadc1);
/* USER CODE BEGIN ADC1_2_IRQn 1 */
/* USER CODE END ADC1_2_IRQn 1 */
}

Reading multiple ADCs with STM32F446RET

i am using the Nucleo64 STM32F446 board and i am trying to read out 3 temperature sensors with the polling method and via DMA but with both methods i can get only 1 correct value. The voltage at every ADC Input is the same. I cannot find the mistake.
Here i drop the polling method: (I just followed this Youtube Tut: https://www.youtube.com/watch?v=5l-b6lsubBE )
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include <math.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
double Temp1 = 0;
double Temp2 = 0;
double Temp3 = 0;
double resistance1;
double resistance2;
double resistance3;
uint16_t ADC_VAL[3];
void ADC_Select_CH1(void){
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void ADC_Select_CH2(void){
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void ADC_Select_CH3(void){
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_112CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE END 0 */
/**
* #brief The application entry point.
* #retval int
*/
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_ADC1_Init();
/* USER CODE BEGIN 2 */
uint16_t x =0;
uint16_t y =0;
uint16_t z =0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
ADC_Select_CH1();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
ADC_VAL[0] = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
ADC_Select_CH2();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
ADC_VAL[1] = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
ADC_Select_CH3();
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
ADC_VAL[2] = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
x = ADC_VAL[0];
y = ADC_VAL[1];
z = ADC_VAL[2];
int resolution = 4096;
resistance1 = 10000*((x/(double)resolution)/(1-(x/(double)resolution)));
resistance2 = 10000*((y/(double)resolution)/(1-(y/(double)resolution)));
resistance3 = 10000*((z/(double)resolution)/(1-(z/(double)resolution)));
Temp1 = 1/((1/298.15)+((double)1/3435)*log((double)resistance1/10000));
Temp2 = 1/ ((1/298.15)+((double)1/3435)*log((double)resistance2/10000));
Temp3 = 1/ ((1/298.15)+((double)1/3435)*log((double)resistance3/10000));
Temp1 = Temp1 - 273.15;
Temp2 = Temp2 - 273.15;
Temp3 = Temp3 - 273.15;
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 180;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Activate the Over-Drive mode
*/
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* #brief ADC1 Initialization Function
* #param None
* #retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
// /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
// */
// sConfig.Channel = ADC_CHANNEL_1;
// sConfig.Rank = 1;
// sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
// Error_Handler();
// }
// /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
// */
// sConfig.Channel = ADC_CHANNEL_2;
// sConfig.Rank = 2;
// sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
// Error_Handler();
// }
// /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
// */
// sConfig.Channel = ADC_CHANNEL_3;
// sConfig.Rank = 3;
// sConfig.SamplingTime = ADC_SAMPLETIME_112CYCLES;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
// Error_Handler();
// }
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* #brief GPIO Initialization Function
* #param None
* #retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
i used PA7 and PA4 instead of PA2 & PA3 for the ADC conversion and it's working. It seems that on this Nucleo Board PA2 & PA3 is not suitable for this task.

Callback in STM32 isn't called

Trying to make simple PWM transmitter i faced with a problem. I have TIM2 with Channel2 (in PWM Generation mode) on board NUCLEO F042K6 and USART1 connected to the board in Async mode (USART works in DMA).
I wanted to make a PWM transmitter that uses a circular buffer that can be filled with one character or several characters at once. The plan was that when the user enters a character (or several characters), the idle line callback is processed, in which a function is called that stores the data in a cyclic buffer. After saving, the data transferred to the buffer is passed to the function PWM_SendChar(...) to convert the data into bits and transfer them over the PWM line. But the problem is when the program goes into PWM_SendChar(...) the callback HAL_TIM_PWM_PulseFinishedCallback(...) isn't called and program stucks in infinite while loop because variable used as a flag for detecting the end of single pulse (PWM_data_sent_flag) wasn't set to value 1.
However, if I use HAL_UART_Recieve(...) func in while(1) loop (located in main(void)) to recieve a char from user program works fine without stucking in while loop in TIM callback. Ofc, for this method I don't use HAL_UARTEx_RxEventCallback(...) and cycle buffer.
Thats's why I think the problem is in USART idle line detection and please help me solve it.
Code Example
Global variable used for waiting the end of pulse:
volatile uint16_t PWM_data_sent_flag = 0;
PWM timer callback:
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
PWM_data_sent_flag = 1;
}
}
Callback for USART idle line:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart == &huart1) {
// Function_to_save_input_char_in_cycle_buffer() is called
}
}
Function used to send char as a PWM signal (emited after Function_to_save_input_char_in_cycle_buffer() completed):
void PWM_SendChar(char ch) {
for (int i = 0, mv = 7; i <= 7; ++i, --mv) {
uint8_t bit = (ch & (1 << mv)) ? 1 : 0;
// PWM_LOW_PERCENT encodes bit with zero value, PWM_HIGH_PERCENT encodes bit with value one
uint16_t duty_cycle = bit == 0 ? PWM_LOW_PERCENT : PWM_HIGH_PERCENT;
// Change TIM2 CCR2 value according to bit's value
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,
GET_PERCENT_VALUE(TIM2->ARR, duty_cycle));
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
// Program comes to this cycle and doesn't leave it
while (!PWM_data_sent_flag)
;
PWM_data_sent_flag = 0;
}
}
USART receive to idle launch (half data transmitted callback disabled):
int main(void) {
// Init code
// ...
if (HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*) ring_buf.buff,
ARRAY_LEN(ring_buf.buff)) != HAL_OK) {
Error_Handler();
}
// Disable half word transmitted callback
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
while(1) {
}
}
TIM2 settings:
static void MX_TIM2_Init(void) {
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
TIM_OC_InitTypeDef sConfigOC = { 0 };
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 48000 - 1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 100 - 1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig)
!= HAL_OK) {
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2)
!= HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
USART1 settings:
static void MX_USART1_UART_Init(void) {
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
DMA settings:
static void MX_DMA_Init(void) {
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel4_5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);
}

while(1) loop in main() stops execute with ADC DMA Access with STM32F072CBT6

I'm using DMA to Access the Data from my ADC. The value at the ADC changes permantenly.
I read I can use DMA so I can use the value of the ADC everytime and everywhere I want to.
Problem is that my Main while() Loop is not or just once execute. The DMA Interupt calls.
HAL_ADC_Start_DMA(&hadc, (uint32_t*) &buffer, 1);
Here is the Code for Start the DMA for the ADC. Mode is Circular.
Here is the Init:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14
|RCC_OSCILLATORTYPE_HSI48;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSI14State = RCC_HSI14_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.HSI14CalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2
|RCC_PERIPHCLK_I2C1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* #brief ADC Initialization Function
* #param None
* #retval None
*/
static void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** 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 = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = ENABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
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;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
The ADC reads a analog volage from I/O.
My while(1) Loop currently just contains blinking led code.
Check the following:
Inside Hal_MSP file use DMA_CIRCULAR
create the buffer like this -> __IO uint16_t buffer[1]
then use it like this -> HAL_ADC_Start_DMA(&hadc, (uint32_t*) &buffer, 1);
Its better to start DMA at the end of ADC init. You can place above line inside the USER CODE BEGIN ADC_Init 2 comment braces.
The ADC size is 12 bit of this controller so circular DMA will automatically overwrite after every conversion.

Individually read distinct inputs with STM32F0 ADC

STM32F072CBU microcontroller.
I have multiple inputs to the ADC and would like to read them individually and separately. STMcubeMX produces boilerplate code which assumes I wish to read all of the inputs sequentially, and I have not been able to figure out how to correct this.
This blog post expresses the same problem I am having, but the solution given doesn't seem to work. Turning the ADC on and off for each conversion correlates with error in the returned value. Only when I configure a single ADC input in STMcubeMX and then poll without de-initializing the ADC are accurate readings returned.
cubeMX's adc_init function:
/* 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_SYNC_PCLK_DIV4;
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 = DISABLE;
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_41CYCLES_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_1;
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_2;
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_3;
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_4;
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__);
}
}
main.c
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();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
//HAL_TIM_Base_Start_IT(&htim3);
init_printf(NULL, putc_wrangler);
HAL_ADCEx_Calibration_Start(&hadc);
HAL_ADC_DeInit(&hadc); // ADC is initialized for every channel change
schedule_initial_events();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
event_loop();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
My process right now for turning the ADC off and reinitializing to change channels:
// Set up
ADC_ChannelConfTypeDef channelConfig;
channelConfig.SamplingTime = samplingT;
channelConfig.Channel = sensorChannel;
channelConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_ADC_ConfigChannel(&hadc, &channelConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
// Convert
uint16_t retval;
if (HAL_ADC_Start(&hadc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_ADC_PollForConversion(&hadc, 1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
if (HAL_ADC_GetError(&hadc) != HAL_ADC_ERROR_NONE)
{
_Error_Handler(__FILE__, __LINE__);
}
retval = (uint16_t) HAL_ADC_GetValue(&hadc);
if (HAL_ADC_Stop(&hadc) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
// Close
HAL_ADC_DeInit(&hadc);
At this point I'm not really sure that there's a way to accomplish what I want, STM32 seems dead set on active ADC lines being in the regular group and being converted in order.
If you want to read several ADC channels in single conversion mode then you have to change the channel setting before each reading, but you do not have to reinit the ADC. Simply do as below, select the new channel (you can change sampling time too if it must be different for the channels but generally it can be the same), select the channel rank and then call the HAL_ADC_ConfigChannel function. After this you can perform a conversion.
void config_ext_channel_ADC(uint32_t channel, boolean_t val)
{
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = channel;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if(True == val)
{
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
}
else
{
sConfig.Rank = ADC_RANK_NONE;
}
HAL_ADC_ConfigChannel(&hadc, &sConfig);
}
uint32_t r_single_ext_channel_ADC(uint32_t channel)
{
uint32_t digital_result;
config_ext_channel_ADC(channel, True);
HAL_ADCEx_Calibration_Start(&hadc);
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 1000);
digital_result = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop(&hadc);
config_ext_channel_ADC(channel, False);
return digital_result;
}
An example for usage:
#define SUPPLY_CURRENT ADC_CHANNEL_5
#define BATTERY_VOLTAGE ADC_CHANNEL_6
uint16_t r_battery_voltage(uint16_t mcu_vcc)
{
float vbat;
uint16_t digital_val;
digital_val = r_single_ext_channel_ADC(BATTERY_VOLTAGE);
vbat = (mcu_vcc/4095.0) * digital_val;
vbat = vbat * 2; // 1/2 voltage divider
return vbat;
}
uint16_t r_supply_current(uint16_t mcu_vcc)
{
float v_sense, current;
uint16_t digital_val;
digital_val = r_single_ext_channel_ADC(SUPPLY_CURRENT);
v_sense = (mcu_vcc/4095.0) * digital_val;
current = v_sense * I_SENSE_GAIN;
return current;
}
This code was used on an STM32F030. For reading the internal temperature sensor and reference voltage a slightly different version of the above seen functions needed as additional enable bits must be set.
void config_int_channel_ADC(uint32_t channel, boolean_t val)
{
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = channel;
if(val == True)
{
if(channel == ADC_CHANNEL_VREFINT)
{
ADC->CCR |= ADC_CCR_VREFEN;
hadc.Instance->CHSELR = (uint32_t)(ADC_CHSELR_CHSEL17);
}
else if(channel == ADC_CHANNEL_TEMPSENSOR)
{
ADC->CCR |= ADC_CCR_TSEN;
hadc.Instance->CHSELR = (uint32_t)(ADC_CHSELR_CHSEL16);
}
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
}
else if(val == False)
{
if(channel == ADC_CHANNEL_VREFINT)
{
ADC->CCR &= ~ADC_CCR_VREFEN;
hadc.Instance->CHSELR = 0;
}
else if(channel == ADC_CHANNEL_TEMPSENSOR)
{
ADC->CCR &= ~ADC_CCR_TSEN;
hadc.Instance->CHSELR = 0;
}
sConfig.Rank = ADC_RANK_NONE;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
}
HAL_ADC_ConfigChannel(&hadc,&sConfig);
}
uint32_t r_single_int_channel_ADC(uint32_t channel)
{
uint32_t digital_result;
config_int_channel_ADC(channel, True);
HAL_ADCEx_Calibration_Start(&hadc);
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 1000);
digital_result = HAL_ADC_GetValue(&hadc);
HAL_ADC_Stop(&hadc);
config_int_channel_ADC(channel, False);
return digital_result;
}
Example usage internal voltage reference for MCU VDD calculation:
#define VREFINT_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7BA))
static float FACTORY_CALIB_VDD = 3.31;
uint16_t calculate_MCU_vcc()
{
float analog_Vdd;
uint16_t val_Vref_int = r_single_int_channel_ADC(ADC_CHANNEL_VREFINT);
analog_Vdd = (FACTORY_CALIB_VDD * (*VREFINT_CAL_ADDR))/val_Vref_int;
return analog_Vdd * 1000;
}
Internal temperature sensor reading:
#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7B8))
#define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7C2))
static float FACTORY_CALIB_VDD = 3.31;
float r_MCU_temp(uint16_t mcu_vcc)
{
float temp;
float slope = ((110.0 - 30.0)/((*TEMP110_CAL_ADDR) - (*TEMP30_CAL_ADDR)));
uint16_t ts_data = r_single_int_channel_ADC(ADC_CHANNEL_TEMPSENSOR);
temp = ((mcu_vcc/FACTORY_CALIB_VDD) * ts_data)/1000;
temp = slope * (temp - (*TEMP30_CAL_ADDR)) + 30;
return round_to(temp, 0);
}
Note that calibration data addresses might be different for your MCU, check the datasheet for more information.
I had the similar problem. I was using STM32F091RC. On ADC_V_PIN I had external multiplexer. On ADC_T_PIN I had NTC reading. I was controlling external multiplexer with GPIOs (this is not seen in the code below). What I needed was multiple successive readings of ADC_V_PIN, after that single ADC_T_PIN reading. With default sequential reading of ADC I would get between each external multiplexed reading of ADC_V_PIN also ADC_T_PIN reading. Using HAL_ADC_ConfigChannel multiple times seemed to OR with each other, and I had problems with reading. So I didn't use HAL_ADC_ConfigChannel at all. Instead, I reconfigured CHSELR register before each software triggered AD conversion. This was the way to make internal and external multiplexer work together.
Here is initialization code:
GPIO_InitStruct.Pin = ADC_V_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(ADC_V_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADC_T_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(ADC_T_PORT, &GPIO_InitStruct);
g_AdcHandle.Instance = ADC1;
if (HAL_ADC_DeInit(&g_AdcHandle) != HAL_OK)
{
/* ADC initialization error */
Error_Handler();
}
g_AdcHandle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
g_AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
g_AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
g_AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;;
g_AdcHandle.Init.ContinuousConvMode = DISABLE;
g_AdcHandle.Init.DiscontinuousConvMode = ENABLE;
g_AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
g_AdcHandle.Init.LowPowerAutoWait = DISABLE;
g_AdcHandle.Init.LowPowerAutoPowerOff = DISABLE;
g_AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
g_AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
g_AdcHandle.Init.DMAContinuousRequests = DISABLE;
g_AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
g_AdcHandle.Init.SamplingTimeCommon = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_Init(&g_AdcHandle) != HAL_OK)
{
/* ADC initialization error */
Error_Handler();
}
if (HAL_ADCEx_Calibration_Start(&g_AdcHandle) != HAL_OK)
{
/* Calibration Error */
Error_Handler();
}
while(1){
ADC1->CHSELR = ADC_CHSELR_CHSEL0;
HAL_ADC_Start(&g_AdcHandle);
HAL_ADC_PollForConversion(&g_AdcHandle, 10);
V = HAL_ADC_GetValue(&g_AdcHandle);
HAL_ADC_Stop(&g_AdcHandle);
ADC1->CHSELR = ADC_CHSELR_CHSEL10;
HAL_ADC_Start(&g_AdcHandle);
HAL_ADC_PollForConversion(&g_AdcHandle, 10);
T = HAL_ADC_GetValue(&g_AdcHandle);
HAL_ADC_Stop(&g_AdcHandle);
}

Resources