This is the 28th day of my participation in the August Text Challenge.More challenges in August

The analog watchdog function of STM8 microcontroller can be used not only in single mode and continuous mode, but also in scanning mode. But in scanning mode the watchdog can only detect one channel.

In scan mode, you need to use the ADC_AWCR register to set the channels that need to enable the analog watchdog function. There are a maximum of 10 channels, but the specific number of channels varies with different microcontrollers and needs to be determined according to the actual model.

After the watchdog interrupt is simulated in scan mode, the corresponding channel flag is set in the ADC_AWSR register, and whether the corresponding channel has an interrupt can be judged by the corresponding flag bit in the interrupt.

The upper and lower limits for simulating the watchdog in scan mode are also set through the ADC_HTR and ADC_LTR registers.

The following figure shows the registers used in scan mode

The single scan mode is used here, and the simulated watchdog function of channel 4 is enabled. Here is a direct example of how to set this up in code:

#include "adc.h"
#include "main.h"

_Bool ADC_flag = 0;                     //ADC conversion success flag

// The AD channel pin is initialized
void ADC_GPIO_Init( void )
{
    PD_DDR &= ~( 1 << 2 );              //PD2 is set as input
    PD_CR1 &= ~( 1 << 2 );              //PD2 is set to dangling input

    PD_DDR &= ~( 1 << 3 );              //PD3 is set as input
    PD_CR1 &= ~( 1 << 3 );              //PD3 is set to dangling input

    PC_DDR &= ~( 1 << 4 );              //PC4 is set as input
    PC_CR1 &= ~( 1 << 4 );              //PC4 is set to dangling input
}

// Set the scan mode to single scan
// Continuously convert data from AIN0-- AINch to ADC channel
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_GPIO_Init();

    ADC_CR1 &= ~( 7 << 4 );   // preload frequency 2
    ADC_CR2 &= ~( 1 << 6 );   // Do not use external triggers
    // Disable the Schmidt trigger for AIN2 and AIN4 to reduce the STATIC power consumption of I/O PD5 and PD6.
    ADC_TDRL |= ( 1 << 2 );
    ADC_TDRL |= ( 1 << 4 );

    ADC_CR1 &= ~( 1 << 1 );   // Single conversion
    ADC_CSR |= 0x04;          // Configure the channel with the largest number
    ADC_CR2 |= ( 1 << 3 );    / / right alignment

    // Set the upper threshold value
    ADC_HTRH = ( u8 )( 800 >> ( u8 )2 );    // Store the top 8 bits of 10 bits of data
    ADC_HTRL = ( u8 )800;                   // Store the lower 2 bits of 10 bits of data

    // Set the lower threshold
    ADC_LTRH = ( u8 )( 300 >> ( u8 )2 );    // Store the top 8 bits of 10 bits of data
    ADC_LTRL = ( u8 )300;                   // Store the lower 2 bits of 10 bits of data

    ADC_AWCRH = 0x00;
    ADC_AWCRL |= ( 1 << 4 );                // Enable the mimic watchdog function on channel 4

    // Analog watchdog interrupts and ADC interrupts cannot be used at the same time, only one can be used at a time
    //ADC_CSR |= ( 1 << 4 ); // Enable watchdog interrupt

    ADC_CR1 |= ( 1 << 0 );    / / open the ADC
    ADC_CR2 |= ( 1 << 1 );    // SCAN = 1 Enable SCAN mode

    ADC_CSR |= ( 1 << 5 );    EOCIE enable transition end interrupt

    // When the ADON bit is set for the first time, the ADC wakes up from low-power mode. To initiate the conversion, the write instruction must be used a second time to set the ADON bits of the ADC_CR1 register.
    for( l = 0; l < 10; l++ );  // Delay to ensure that the ADC module is powered on for at least 7us
    ADC_CR1 |= ( 1 << 0 );      // Again enable ADC at the lowest position 1 of register CR1 and begin conversion
}
u16 ain2_val = 0, ain3_val = 0, ain4_val = 0;
u16 temph = 0;
u8 templ = 0;
// Read the sample voltage value
u16 ReadVol_CHx( void )
{
    u16 voltage = 0;

    if( ADC_flag == 1 )
    {
        ADC_flag = 0;
        // Single channel scan mode, the conversion result is stored in the ADC_DBxR register
        // Read the value of AIN2
        templ = ADC_DB2RL;
        temph = ADC_DB2RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8)); ain2_val = temph;// Read the value of AIN3
        templ = ADC_DB3RL;
        temph = ADC_DB3RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8)); ain3_val = temph;// Read the value of AIN4
        templ = ADC_DB4RL;
        temph = ADC_DB4RH;
        temph = ( u16 )( templ | ( u16 )( temph << ( u16 )8)); ain4_val = temph; ADC_CR1 |=0x01;                        // Start a conversion
    }
    return voltage;
}
//AD interrupt service function Interrupt number 22
#pragma vector = 24                     // Interrupt number in IAR, add 2 to interrupt number in STVD
__interrupt void ADC_Handle( void )
{
    // Bit clearing cannot be used in scan mode
    if( ADC_CSR & ( 1 << 7 ) )
    {
        ADC_CSR = ADC_CSR & ( ~( 1 << 7)) |0x04;  // Clear the EOC flag bit
    }
    if( ADC_AWSRL & ( 1 << 4 ) )
    {
        ADC_AWSRL &= ~( 1 << 4 );
    }
    if( ADC_CSR & ( 1 << 6 ) )
    {
        ADC_CSR = ADC_CSR & ( ~( 1 << 6)) |0x04;  // Simulate watchdog flag bit to clear AWD
    }
    ADC_flag = 1;                       // Set the ADC interrupt flag to 1
}
Copy the code

The Settings for simulating the watchdog in the initialization code are as follows:

   // Set the upper threshold value
    ADC_HTRH = ( u8 )( 800 >> ( u8 )2 );    // Store the top 8 bits of 10 bits of data
    ADC_HTRL = ( u8 )800;                   // Store the lower 2 bits of 10 bits of data

    // Set the lower threshold
    ADC_LTRH = ( u8 )( 300 >> ( u8 )2 );    // Store the top 8 bits of 10 bits of data
    ADC_LTRL = ( u8 )300;                   // Store the lower 2 bits of 10 bits of data

    ADC_AWCRH = 0x00;
    ADC_AWCRL |= ( 1 << 4 );                // Enable the mimic watchdog function on channel 4
Copy the code

First set the upper and lower limits of the simulated watchdog, where the upper limit is 800 and the lower limit is 300, and then turn on the simulated watchdog function of channel 4. Set here need to scan the channel followed by 2, 3, 4, only when the channel 4 samples values less than 300 or above 800, analog watchdog would raise the interrupt, while channel 2, and 3 value no matter what, analog watchdog will not raise the interrupt, that is to say, analog watchdog only work on channel 4. To monitor the value of channel 2 or channel 3, reset the value of the ADC_AWCRL register.

Analog watchdog interrupt and ADC sampling interrupt entry function are the same function, so three flag bits need to be judged in the interrupt function, one is sampling interrupt flag, one is simulated watchdog interrupt flag, and one is simulated watchdog channel flag.

A problem can be found in the interrupt code, that is, the way to clear the interrupt flag bit of the ADC_CSR register is a bit strange, not directly through the bit operation to achieve, but a lot of things, why is this?

First, take a look at the introduction in the official documentation

Instructions for channel bit operations cannot clear the sampling interrupt flag bit in scan mode.

In the ADC_CSR register, it can be seen that the highest bit EOC is the end of conversion flag bit, and the lowest 4 bits are the conversion channel bit. The reason for not being able to operate directly is that the lowest four bits of the channel are variable in scan mode. Due to the need to scan 2, 3, 4 fold three channels in turn, so when the need to scan that channel, the corresponding channel bit will be automatically set by the SCM hardware. When the EOC bit is cleared by bit operation, CH is also cleared to 0. In this case, the scanning mode will not continue after the interruption. In other words, the program will be abnormal if the number of channels is set to 0. Therefore, when clearing EOC flag bits in scan mode, one-time write is required. While writing, you need to reset the sampling channel value. ADC_CSR = ADC_CSR & ( ~( 1 << 7 ) ) | 0x04;

So we’re going to move 1 to the left by 7 bits and then invert it, so we’re going to invert EOC, which is the highest EOC bit, which is the same thing as clearing out the EOC bit. Finally, 0x04 performs or operation, which is to reset the maximum channel value of the scan. Since the maximum channel number sampled here is 4, the maximum channel value is also set to 4. After the EOC bit is cleared in this way, the scanning channel setting will not be affected.

The main function reads the values of the three channels directly.

#include "iostm8s103F3.h"
#include "led.h"
#include "adc.h"
#include "stdio.h"
void SysClkInit( void )
{
    CLK_SWR = 0xe1;       //HSI 16MHz CPU clock frequency of the primary clock source
    CLK_CKDIVR = 0x00;    //CPU clock is 0, system clock is 0
}
void main( void )
{
    SysClkInit();
    __asm( "sim" );                       // Disable interrupts
    LED_GPIO_Init();
    ADC_CH_Init( 4 );
    __asm( "rim" );                       // Enable interrupts
    while( 1) { LED = ! LED;// It takes 10uS to run a loopReadVol_CHx(); }}Copy the code

The channel sampling function is read circularly in the main function. When the sampling voltage of channel 4 is lower than 300 or higher than 800, the flag bit of simulated watchdog will be set. There’s one more thing to note here.

ADC sampling interrupts and analog watchdog interrupts cannot be used together.

The code uses ADC sampling interrupts, not analog watchdog interrupts. To use analog watchdog interrupts, the ADC sampling interrupts must be turned off. When both interrupts are enabled at the same time, the ADC scan mode seems to be affected, causing the scan mode to fail after entering the interrupt once. According to the official manual, no bit clearing operation is also not allowed. Maybe there is a conflict between the two interrupts in the chip. There is no specific explanation in the official manual, so the real reason is not known.