Skip to main content
Visitor II
February 5, 2024
Solved

[STM32L475] ADC channel reading problem getting unexpected value

  • February 5, 2024
  • 1 reply
  • 1901 views

Hi all,

 

I have a problem which is bugging me as I can't figure out what im doing wrong.

I am trying to read from ADC_IN4 but are reading wrong values. I should be reading apprx. 30000 ADC value but i am reading apprx. 7800. I think that this indicates that i am not reading from the right channel because there is a LM20 temperature sensor connected to PC3 which is ADC_IN4 on stm32L475x and the value does not change if i apply heat or cold.

I want the TIM4_TRGO event to trigger ADC conversions with 16x oversampling, and at sequence end, trigger EOS interrupt where i read the ADC data. Later on i want to connect it to DMA.

I have never really worked with update events on stm32 so I think I am maybe doing something wrong setting up the update events, maybe im mixing up interrupts and events, or the ADC channel configuration is wrong.

I really hope someone can help me.

Thanks.

#include "stm32l475xx.h"
#include "variables.h"
volatile uint32_t count = 0;
volatile uint32_t result = 0;

void sysclk_config(){
 RCC->CR |= RCC_CR_HSEON; // turn on HSE clock
 // wait until hardware sets this bit to indicate HSE is ready
 while(!(RCC->CR & RCC_CR_HSERDY));
 RCC->CFGR |= RCC_CFGR_SW_HSE; // Use HSE as system clock

 // Check status of HSE as system clock
 while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE);
 RCC->CR &= ~(1<<0); //MSI OFF

PWR->CR1 |= (1U<<9U);
}

void peripheralClk_config(){
 RCC->AHB2ENR |= RCC_AHB2ENR_ADCEN; // Enable clock for ADC.
 
 RCC->CCIPR |= (3U<<28); // set ADC clock as system clock
 
 RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // Enable clock for DMA1
 
 RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN; // Enable clock for GPIO C
 
 RCC->AHB2ENR |= RCC_AHB2ENR_GPIOHEN; // Enable clock for GPIO H
 
 RCC->APB1ENR1 |= RCC_APB1ENR1_TIM4EN;
}

void GPIOC_setup(){
 GPIOC->MODER |= (0x3U << 0U); // GPIOC Mode register for PC0 = 3 Analog mode
 
 GPIOC->PUPDR &= ~(0x3U << 0U); // No pull up/Pull down
 
 GPIOC->MODER |= (3U << 6U); // GPIOC Mode PC3 = 3 (Analog mode)
 
 GPIOC->PUPDR &= ~(3U << 6U); // No pull-up/pull-down
 
 GPIOC->ASCR |= (1U<<4U); // Analog switch
}

void ADC2_setup() {

 ADC2->CR &= ~ADC_CR_DEEPPWD; // wake up ADC from deep power down

 ADC2->CR |= ADC_CR_ADVREGEN;

 uint32_t wait_loop_index;
 wait_loop_index = (((20UL) * (16000000 / (100000 * 2))) / 10);
 while(wait_loop_index != 0){
 wait_loop_index--;
 }
 // Enable Vref
 (*(volatile uint32_t*)((0x50040300) + (0x08)) |= (1U << 22U)); 
 

 ADC2->CR |= ADC_CR_ADCAL; // Start calibration;


 // EXT Line 12 for TIM4_TRGO
 while (ADC2->CR & ADC_CR_ADCAL); // Wait for calibration to complete
 
 ADC2->CFGR |= (ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_2); 
 ADC2->CFGR |= (0x1U << 10U); // Hardware trigger on rising edge
 ADC2->CFGR2 |= (0x3UL << 2U); // 16x oversampling
 ADC2->CFGR2 |= (0x00U << 5U); // no bit shift
 ADC2->CFGR2 |= (1U<<0U); // regular oversampling enable
 ADC2->IER |= ADC_IER_EOSIE; // end of sequence interrupt enable
 ADC2->SQR1 &= ~ADC_SQR1_SQ1; // Clear sequence register
 ADC2->SQR1 |= (0x4U << 6U); // Channel 4 is 1st conversion
 ADC2->SMPR1 &= ~ADC_SMPR1_SMP3; // clear sampletime register
 ADC2->SMPR1 |= (0U << 9U); // 2.5 Sample time for channel 4
 NVIC_EnableIRQ(ADC1_2_IRQn);
 ADC2->CR &=\~ ADC_CR_ADDIS;
 ADC2->CR |= ADC_CR_ADEN;
 while (!(ADC2->ISR & ADC_ISR_ADRDY));
}

void ADC_Start(void){

 ADC2->CR |= ADC_CR_ADSTART;
}

void ADC1_2_IRQHandler(void){
 if (ADC2->ISR & ADC_ISR_EOS){ // Check if end of sequence flag is set

 result = ADC2->DR; // Read from ADC Data Register
 ADC2->ISR &= ~ADC_ISR_EOS; // Clear end of sequence flag.

 ADC2->CR |= ADC_CR_ADSTART;
 }
}
void TIM4_ADC_setup(){ // Function for setting up the ADC timer 16kHz
 TIM4->PSC = 1; // Set prescaler
 TIM4->ARR = 119; // Set auto-reload value
 TIM4->CR1 &= ~(1U<<7U); // ARR not buffered
 TIM4->CR1 &= ~(3U<<8U); // no clock division
 TIM4->CR2 |= TIM_CR2_MMS_1;
 TIM4->EGR |= TIM_EGR_UG; // Update generation
 TIM4->DIER |= TIM_DIER_UIE;

 NVIC_EnableIRQ(TIM4_IRQn);

 TIM4->CR1 |= TIM_CR1_CEN; // Start the timer
}

void TIM4_IRQHandler(void) {
 if (TIM4->SR & TIM_SR_UIF) { // Check if update interrupt flag is set
 TIM4->SR &= ~TIM_SR_UIF; // Clear update interrupt flag
 }
}

int main(void){
 __enable_irq();
 sysclk_config();
 peripheralClk_config();
 GPIOC_setup();
 TIM4_ADC_setup();
 ADC2_setup();
 ADC_Start();
 while(1){
 }
}
    This topic has been closed for replies.
    Best answer by TDK

    > Shorting to GND or Vref also makes no difference.

    Then probably that pin isn't connected to what you think it is, or it's not configured correctly.

    > GPIOC->ASCR |= (1U<<4U); // Analog switch

    Should be 1U << 3U to set ASC3, yes?

    1 reply

    Super User
    February 5, 2024

    > ADC2->SMPR1 |= (0U << 9U); // 2.5 Sample time for channel 4

    This is a very short sample time. Consider increasing it to max. Temperature doesn't change that quickly.

    Short the input to GND, do you get 0 (or close to)? Short it to VREF+, do you get 65536, or close to?

     

    AKAKAuthor
    Visitor II
    February 5, 2024

    I tried setting sampletime to max but nothing changed. 

    Shorting to GND or Vref also makes no difference.

    TDKAnswer
    Super User
    February 5, 2024

    > Shorting to GND or Vref also makes no difference.

    Then probably that pin isn't connected to what you think it is, or it's not configured correctly.

    > GPIOC->ASCR |= (1U<<4U); // Analog switch

    Should be 1U << 3U to set ASC3, yes?