0

I am trying to use interrupts with the ADC module. I am using PA0 and PA1 as analog inputs for the ADC, and PC0 and PC1 as external LEDs. My goal is: when PA0 is triggered, PC0 should turn on. when PA1 is triggered, PC1 should turn on.

However, I am facing a problem: when I apply 3.3V to PA0, both LEDs turn on. And when I try to trigger PA1, nothing happens. I think there are two logical errors, but I cannot figure them out. Also there are no hardware or cable issues in the circuit.

#include "main.h"
volatile uint8_t adc_index = 0;
void SystemClock_Config(void);
void ADC_IRQHandler(void)
{
    if(ADC1->SR & (0x1 << 1))
    {
        uint8_t val = (uint8_t)ADC1->DR;
        if(adc_index == 0)
        {
            if(val > 127)
                GPIOC->BSRR = (1 << 0);
            else
                GPIOC->BSRR = (1 << 16);
        }
        else
        {
            if(val > 127)
                GPIOC->BSRR = (1 << 1);
            else
                GPIOC->BSRR = (1 << 17);
        }
        adc_index++;
        if(adc_index >= 2) adc_index=0;
    }
}

int main(void)
{

  HAL_Init();
  SystemClock_Config();

  RCC->AHB1ENR |= (0x5 << 0);
  RCC->APB2ENR |= (0x1 << 8);

  // PA0 as Analog Input for ADC
  GPIOA->MODER |= (0x3 << 0);
  // PA1 as Analog Input for ADC
  GPIOA->MODER |= (0x3 << 2);
  // PC1 as General output for external Led
  GPIOC->MODER &= ~(0x3 << 2);
  GPIOC->MODER |= (0x1 << 2);
  // PC0 as General output for external Led
  GPIOC->MODER &= ~(0x3 << 0);
  GPIOC->MODER |= (0x1 << 0);

  // ADC Cont mode on
  ADC1->CR2 |= (0x1 << 1);
  // Interrupt enable for ADC
  ADC1->CR1 |= (0x1 << 5);

  // 8 bit Resolution
  ADC1->CR1 &= ~(0x3 << 24);
  ADC1->CR1 |= (0x2 << 24);

  // 2 Channel conversion
  ADC1->SQR3 |= (0x0 << 0);
  ADC1->SQR3 |= (0x1 << 5);

  // 2 CONVERSION Selected
  ADC1->SQR1 |= (0x1 << 20);

  // Sample Rate 84 CYCLES
  ADC1->SMPR2 &= ~(0x7 << 0);
  ADC1->SMPR2 |= (0x4 << 0);

  // ADC_IRQHandler unmasked
  NVIC->ISER[0] = (0x1 << 18);

  // ADC On
  ADC1->CR2 |= (0x1 << 0);

  // Software Start
  ADC1->CR2 |= (0x1 << 30);

  while (1)
  {

  }

}

1
  • stop using magic numbers - you ahve nice macrodefinitions in CMSIS. Commented Sep 30 at 21:29

1 Answer 1

2

The configuration of the ADC is incorrect for two channels as the result only one ADC channel is running.

  1. ADC_CR1_SCAN bit need to be enabled for more than 1 channel scan;

  2. To have each ADC channel to be triggered by the interrupt, ADC_CR2_EOCS bit need to be enabled. Otherwise, only one interrupt would be generated at end of the sequence of all channel conversions.

  3. Only one channel is configured to have sample rate of 84 cycles, you might want to setup the sample rate for the 2nd channel with

ADC1->SMPR2 |= ADC_SMPR2_SMP0_2   // ch0 bit2 set = 84 sample cycle
            |  ADC_SMPR2_SMP1_2;  // ch1 bit2 set = 84 sample cycles

Use pre-defined CMSIS definitions instead of magic number.

ADC1->CR2 |= ADC_CR2_SWSTART;

is more readable than

ADC1->CR2 |= (0x1 << 30);
Sign up to request clarification or add additional context in comments.

2 Comments

I changed the code just like you said. But now when I apply voltage to PA0 or PA1, both LEDs turn on.
Sorry, didn't pay too much attention to the LED and the ISR handler. I saw the ADC configuration and went on to point out the proper configuration. For Continuous Mode, ST actually recommended to use in conjunction with DMA instead of using Interrupt. You might want to read this gotcha, alternatively, you could configure the ADC to run in Discontinuous mode.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.