2023-03-18 02:18 AM
I have initialized ADC1 and assigned it 4 channels (PA4-PA7 as IN4 to IN7). My initialization looks like this:
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_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
I would like to read all 4 channels one after another (they represent pot positions). How can I address each channel? This is the code I'm trying but I don't see any specific channel being addressed. Rather than the one specified in the initialization.
The is the read loop:
while (1)
{
char buffer[8];
int ADCValue;
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
//delay_us(50);
delay_ms(10);
//pin_state = !pin_state;
//HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, pin_state);
// synchronous delay for 500 ms
//HAL_Delay(100);
if (HAL_ADC_Start(&hadc1) != HAL_OK)
{
/* Start Conversation Error */
Error_Handler();
}
if (HAL_ADC_PollForConversion(&hadc1, 500) != HAL_OK)
{
/* End Of Conversion flag not set on time */
// Error_Handler();
ADCValue=-1;
}
else
{
/* ADC conversion completed */
ADCValue = HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);
sprintf(buffer,"%d",ADCValue);
lcd_setcursor(0,1);
lcd_string(buffer);
/* USER CODE END 3 */
}
2023-03-18 11:46 AM
Which STM32? There are many different versions.
2023-03-18 11:55 AM
Add configuration for IN5 to IN7 as ranks 2 to 4, Make nbrofconversion = 4
Edit: And since there is only one ADC conversion result register, save the results into a 4 16bit word buffer using DMA. Without DMA you could poll for each channel and reconfigure the ADC for the next conversion after each conversion, but that would not be compatible with the continuous conversion goal.
And reading pots with few sample cycles usually results in inaccurate results. See ST's Application Note AN2834 for more information.
2023-03-19 12:51 AM
Sorry, forgot: STM32F103C8T6
2023-03-19 01:22 AM
@raptorhal2 Thanks for pointing me to that AN2834. It is a very voluminous document covering ADC errors and accuracy. Averaging samples is also mentioned. Nothing about pots in particular.
And programming examples for setting up DMA and the desired 4 channel configuration would be very welcome at the moment. Averaging comes later :)
2023-03-19 07:51 AM
Nothing about pots in particular.
A pot is a high impedance device. How high depends on the pot and setting. The output of an operational amplifier would be a low impedance device, where 1,5 cycles could be used.
programming examples for setting up DMA
The Standard Peripheral and HAL libraries for the F103 come with ADC DMA examples. You may have to expand the example buffer size and configuration ranks to 4.
2023-03-29 01:09 AM
Sorry, misedited.
2023-03-29 01:11 AM
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 = 4;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_7;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
I'm still doing something wrong. ADC values are not sorted in as expected:
ADC: 1839 2112 0 1257
ADC: 1263 2112 0 1257
ADC: 1254 1835 2107 1
ADC: 0 1258 1839 2111
ADC: 6 1262 1840 2107
ADC: 2108 1 1257 1836
void StartTask03(void *argument)
{
/* USER CODE BEGIN StartTask03 */
// ADC CAlibration
HAL_ADCEx_Calibration_Start(&hadc1);
osDelay(50);
/* Infinite loop */
for(;;)
{
char str[32];
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&adc_value[0], 4);
sprintf(str,"ADC: %d %d %d %d \n",adc_value[0],adc_value[1],adc_value[2],adc_value[3]);
uart1_print(str);
osDelay(5000);
}
/* USER CODE END StartTask03 */
}