STM32 + FreeRTOS + Analog WatchDog

Hi guys, I’m trying to set up Analog WatchDog on a Bluepill with FreeRTOS, but I can’t find any documentation about it.

All I find is using the “STM32CubeIDE” application, but I need to be able to configure and program it directly from my PlatformIO code.

Basically, I need an interrupt to be triggered when an analog pin reaches a certain voltage. I’d also like to know if I can change this voltage in real time, based on other input parameters.

I use:

framework = arduino

In code: #include <STM32FreeRTOS.h>

Can anyone help me?

Regards!

I don’t see there being a ready-made Arduino library that wraps the Analog Watchdog functionality, but since the Arduino core is built on top of the STM32HAL, you can call into normally.

Below is an example for PA0 and the some voltage threshholds. You should be able to reconfigure the upper and lower voltages on the fly by just writing

  WRITE_REG(hadc->Instance->HTR, HighThreshold);
  WRITE_REG(hadc->Instance->LTR, LowThreshold);

as needed. In the interrupt / calllback function HAL_ADC_LevelOutOfWindowCallback, you may of course also use a FreeRTOS primitive to send a notification to a FreeRTOS task, causing it to wake up, instead of setting a volatile bool variable here. Also see https://deepbluembedded.com/stm32-analog-watchdog-adc-mode-code-example/ for reference.

#include <Arduino.h>

/* Example: PA0  */
#define ADC_PORT        GPIOA
#define ADC_PIN         GPIO_PIN_0      // Change to any ADC-capable pin
#define USED_ADC        ADC1            // Change to ADC2 if using ADC2
#define GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define ADC_CHANNEL     ADC_CHANNEL_0   // must match pin (or special internal channel)
/* trigger analog watchdog if below LOW or above HIGH */
#define LOW_THRESHOLD   1000            // 0–4095 (12-bit ADC)
#define HIGH_THRESHOLD  3000            // 0–4095

ADC_HandleTypeDef hadc;
volatile bool watchdogTriggered = false;

void SystemClock_Config(void);
void MX_ADC_Init(void);

void setup() {
    Serial.begin(115200);
    delay(2000);
    Serial.println("Analog Watchdog Example");
    // Enable all ADC clocks to be safe
    __HAL_RCC_ADC1_CLK_ENABLE();
    __HAL_RCC_ADC2_CLK_ENABLE();
    MX_ADC_Init();
    // Start ADC in interrupt mode
    HAL_StatusTypeDef status = HAL_ADC_Start_IT(&hadc);
    if (status != HAL_OK) {
        Serial.println("Failed to start ADC interrupt mode");
    } else {
        Serial.println("ADC started in interrupt mode");
    }
}

void loop() {
    // check if the watchdog was triggered and print a message
    if (watchdogTriggered)
    {
        watchdogTriggered = false;
        Serial.println("⚠ Analog Watchdog Triggered!");
    }
    delay(10);
}

void MX_ADC_Init(void) {
    GPIO_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin  = ADC_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(ADC_PORT, &GPIO_InitStruct);

    ADC_ChannelConfTypeDef sConfig = {0};
    ADC_AnalogWDGConfTypeDef awdConfig = {0};

    hadc.Instance = USED_ADC;
    hadc.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc.Init.ContinuousConvMode = ENABLE;
    hadc.Init.DiscontinuousConvMode = DISABLE;
    hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc.Init.NbrOfConversion = 1;

    HAL_ADC_Init(&hadc);

    // Configure selected ADC channel
    uint32_t channel = ADC_CHANNEL;

    sConfig.Channel = channel;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;

    HAL_ADC_ConfigChannel(&hadc, &sConfig);

    // Configure Analog Watchdog
    awdConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
    awdConfig.Channel = channel;
    awdConfig.ITMode = ENABLE;
    awdConfig.HighThreshold = HIGH_THRESHOLD;
    awdConfig.LowThreshold = LOW_THRESHOLD;

    HAL_ADC_AnalogWDGConfig(&hadc, &awdConfig);

    // Enable ADC interrupt in NVIC
    HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}

/* Interrupt handler */
extern "C" void ADC1_2_IRQHandler(void) {
    HAL_ADC_IRQHandler(&hadc);
}

/* callback from STM32HAL if watchdog triggered */
extern "C" void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef *hadc) {
    watchdogTriggered = true;
}

Thanks for your reply, will try it…