In STM32F103, How to create two timer interrupt running without disturb each other?

You’re missing the interrupt handler for the ADC that actually triggers this callback.

extern "C" void ADC1_2_IRQHandler(void) {
  HAL_ADC_IRQHandler(&hadc1);
}

I’ve verified that this example works fine:

#include <Arduino.h>

ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim3;

void init_adc_and_tim() {
    __HAL_RCC_ADC1_CLK_ENABLE();

  ADC_ChannelConfTypeDef sConfig = {0};
  /* Common config */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
  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_0;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){
    Error_Handler();
  }
  /* TIM3 Init */
  __HAL_RCC_TIM3_CLK_ENABLE();
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 7200 - 1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 100 - 1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK) {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) {
    Error_Handler();
  }

  // Enable interrupt for ADC1_2
  HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}

/* interrupt handler for ADC */
extern "C" void ADC1_2_IRQHandler(void) {
  HAL_ADC_IRQHandler(&hadc1);
}

static volatile uint16_t adcValue = 0;
static volatile bool adcChanged = false;

/* called by the HAL ADC in interrupt context when conversion is complete */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if (hadc->Instance == ADC1) {
        adcValue = (uint16_t) HAL_ADC_GetValue(hadc);
        adcChanged = true;
    }
}

void setup() {
    Serial.begin(921600);
    // use one analogRead to setup pin correctly in analog mode
    (void) analogRead(PA0);
    init_adc_and_tim();
    // kick off timer to generate TRGO events
    HAL_TIM_Base_Start(&htim3);
    // kick off process once
    HAL_ADC_Start_IT(&hadc1);
}

void loop() {
    if (adcChanged) {
        __disable_irq(); // so that the value doesn't change as we read it out
        String line = "[" + String(millis()) + "] New ADC value: " + String(adcValue);
        adcChanged = false;
        __enable_irq();
        Serial.println(line);
    }
}

It consistently produces a new ADC value every 10 milliseconds, which is 100 Hz.

grafik

This example still doesn’t use DMA to transfer the value from the ADC peripheral into a e.g. (circular) RAM buffer, but it’s a start. Now, the interrupt processing time for the ADC should be much, much lower than before, because the ADC result is already available.

1 Like