2024-05-19 07:10 PM
This should be easy but somehow I cannot make it work? I am working with the ADC of my STM23F4 Board trying to read the input from an AC voltage sensor. My previous code was using HAL and it was outputting my desired values (around 2000), but when I translated the code to standard register programming, the output is wrong (only around 25). What could be the problem with my initialization? There were other ADC initializations in the HAL code for the injected channels but I figured I dont need them in my other code. I am also using the system clock to implement delays with the systick handler, so that shouldn't be a problem anymore. Are there other important details that I missed? Thank you in advance for your help.
#include <stdint.h>
#include <stm32f4xx.h>
#include <stm32f411xe.h>
uint16_t adc_value = 0b0000;
uint16_t temp_bit = 0b0000;
uint16_t mask = 0b0000;
uint16_t move = 0b0000;
void GPIO_init(void);
void ADC_init(void);
void ADC_enable(void);
void ADC_startconv(void);
void ADC_waitconv(void);
int ADC_GetVal(void);
void delay_ms(int delay);
void GPIO_init(void) {
//enable GPIOA clock
RCC->AHB1ENR |= (1 << 0);
//configure PA1 to analog mode
GPIOA->MODER |= (1 << 3);
GPIOA->MODER |= (1 << 2);
//enable GPIO B clock
RCC->AHB1ENR |= (1 << 1);
//configure PB1 as output
GPIOB->MODER &= ~(1 << 3);
GPIOB->MODER |= (1 << 2);
//configure PB1 as push-pull output
GPIOB->OTYPER &= ~(1 << 1);
//set to high as initial state
GPIOB->ODR |= (1 << 1);
}
void ADC_init(void) {
//enable adc clock
RCC->APB2ENR |= (1 << 8);
//prescaler div 4
ADC->CCR |= (1 << 16);
ADC->CCR &= ~(1 << 17);
//configure ADC resolution = 12bits (00)
ADC1->CR1 &= ~(1 << 25);
ADC1->CR1 &= ~(1 << 24);
//Disable Scan mode
ADC1->CR1 &= ~(1 << 8);
//Disable Continuous conversion mode
ADC1->CR2 &= ~(1<<1);
//Disable Discontinuous Conversion Mode
ADC1->CR1 &= ~(1<<11);
//No external trigger conversion edge
ADC1->CR2 &= ~(1<<28);
ADC1->CR2 &= ~(1<<29);
//ADC conversion at software start (EXTSEL config doesn't matter because exten is 00
ADC1->CR2 &= ~(1<<27);
ADC1->CR2 &= ~(1<<26);
ADC1->CR2 &= ~(1<<25);
ADC1->CR2 &= ~(1<<24);
//External trigger conversion set to software start
// ADC1->CR1 |= (1 << 5);
//configure sampling time of channel 1 to 15 per cycle
ADC1->SMPR2 &= ~(1 << 5);
ADC1->SMPR2 &= ~(1 << 4);
ADC1->SMPR2 |= (1 << 3);
//reqular sequence rank 1 to channel 1
//configure data alignment
ADC1->CR2 &= ~(1 << 11);
//total number of conversions in the channel conversion sequence set to 1
ADC1->SQR1 &= ~(1 << 23);
ADC1->SQR1 &= ~(1 << 22);
ADC1->SQR1 &= ~(1 << 21);
ADC1->SQR1 &= ~(1 << 20);
//DMA Continuous Requests DISABLE
ADC1->CR2 &= ~(1<<9);
//EOCS Single Conversion
ADC1->CR2 &= ~(1<<10);
//assign channel for first conversion
//ADC1->SQR3 |= (1 << 0);
}
void ADC_enable(void) {
ADC1->CR2 |= (1 << 0); //enable the adc
delay_ms(1); // required to ensure adc stable
}
void ADC_startconv(void) {
ADC1->CR2 |= (1 << 30);
}
void ADC_waitconv(void) {
//wait for the end of conversion
while (!((ADC1->SR) & (1 << 1))) {
;
}
}
int ADC_GetVal(void) {
return ADC1->DR; //read the value contained at the data register
}
The HAL version is this:
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
ADC_InjectionConfTypeDef sConfigInjected = {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; //done
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //done
hadc1.Init.Resolution = ADC_RESOLUTION_12B; //done
hadc1.Init.ScanConvMode = DISABLE; //done
hadc1.Init.ContinuousConvMode = DISABLE; //done
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; //done
hadc1.Init.NbrOfConversion = 1; //done
hadc1.Init.DMAContinuousRequests = DISABLE; //done?? ADC1->CR2 &= ~(1<<9);
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //done
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_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_0;
sConfigInjected.InjectedRank = 1;
sConfigInjected.InjectedNbrOfConversion = 1;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_NONE;
sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
2024-05-20 03:01 AM - edited 2024-05-20 03:02 AM
You don't want to comment this out for converting CH1:
//assign channel for first conversion
//ADC1->SQR3 |= (1 << 0);
Read out and check/post content of ADC and relevant GPIO registers.
Show, how exactly do you perform the conversion and how do you check the resulting value.
Use the debugger for experimenting with ADC.
JW
PS. Style: do use symbols from the CMSIS-mandated header, write registers values at once not bit-per-bit