This is the 29th day of my participation in the August Wenwen 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.

For scan mode, the channel can be set through the ADC_AWCR register, but there is only one set of registers to set the upper and lower registers, so by this inference, the analog watchdog function can only be used in one channel at a time.

The simulated watchdog upper limit is set through the following two registersThe ADC_HTRH register sets the upper limit 8 bits, and ADC_HTRL sets the lower limit 2 bits.

The ADC_LTRH register sets the upper 8 bits of the lower limit, and ADC_LTRL sets the lower 2 bits of the lower limit.

The Settings of these four registers should be subject to the official English materials. The introduction of these four registers in the official STM8 Chinese manual is wrong. This problem has also been explained in detail in other articles, so it will not be specified here.

After setting the upper and lower limits, enable the corresponding channel to simulate the watchdog function

The ADC_AWCRH register is set to channels 8 and 9, and the ADC_AWCRL register is set to channels 0 to 7. Here, analog channel 4 needs to be monitored, so only the fourth bit of the ADC_AWCRL register needs to be set to 1.

The following is a direct example of the code to enable the simulated watchdog function of channel 4 in continuous scan mode.

#include "adc.h"
#include "main.h"
#include "led.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 to continuous scan mode
// 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 );   // Continuous conversion
    ADC_CSR |= 0x04;          // Configure the channel with the largest number
    ADC_CR2 |= ( 1 << 3 );    / / right alignment

    ADC_CR1 |= ( 1 << 0 );    / / open the ADC
    ADC_CR2 |= ( 1 << 1 );    // SCAN = 1 Enable SCAN mode
    
    // 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

    // Only one watchdog interrupt and ADC interrupt can be used at a time.
    //ADC_CSR |= ( 1 << 4 ); // Enable watchdog interrupt

    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; }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 )
{
    if( ADC_CSR & ( 1 << 7))// The EOC flag cannot be cleared by bit operations
    {
        ADC_CSR = ADC_CSR & 0x7F | 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

During initialization, the continuous scan mode is enabled first. The maximum number of channels to be scanned is 4, that is, from channel 0 to channel 4. Then set the upper and lower limits of the simulated watchdog, enable the simulated watchdog function of channel 4, and enable the sampling function.

Note the following when clearing flag bits in interrupts:

Note: In scan mode (continuous scan mode), do not use the bit operation instruction (BRES) to clear the EOC flag bits, because this instruction is a read-modify-write operation on the entire ADC_CSR register. Reading the current channel number from the CH[3:0] register and writing it back will change the last channel number of the scanned series. The correct way to clear the EOC flag bit in continuous scan mode is to load a byte from a RAM variable into the ADC_CSR register to clear the EOC flag bit and reload the new last channel number of the scan series. Experiments show that the bit-operation instruction clears the values in the CH[3:0] register only in continuous scan mode, but does not affect other values. Therefore, read out the value in ADC_CSR, add the original channel number in CH[3:0], and write it back to ADC_CSR. It is written as follows:

ADC1->CSR = (uint8_t)(ADC1->CSR &(~ADC1_FLAG_EOC)|ADC1_CHANNEL_n);

Note: ADC1_CHANNEL_n indicates the end of the channel.

So using ADC_CSR in interrupt = ADC_CSR & 0 x7f | 0 x04; To clear the flag bit. Clears the highest bit with 0x7F, and then or 0x04 is used to reset the maximum sampling channel. In this way, the value of the scan channel will not be affected when the flag bit is cleared. Because in scan mode, the value in register CH[3:0] will constantly change, and when the value of the current channel is sampled, the corresponding bit will be automatically set to 1 by hardware. When the sampling starts, the value in register CH[3:0] will change from time to time. If the EOC flag bit is cleared by bit operation directly in interrupt, The value in register CH[3:0] will also be set to 0, so that after the interrupt ends, scan mode will be invalid, resulting in program operation errors.

The scan function is then called directly from the main function to read the results

#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;               
       ReadVol_CHx();
    }
}
Copy the code

In the main program, the ReadVol_CHx() function is called to read the sampling result. When the sampling voltage value of channel 4 is less than 300 or more than 800, the fourth bit of the ADC_AWSRL register will be set to 1, indicating that an analog watchdog event has occurred.

One other thing to note here is that 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, it is not possible to use the bit zero clearing operation. 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.