Continuing the STM8 Expedition

STM8S105 Discovery

Multi-Channel ADC with Scan Mode

When it is required to sense and measure multiple analog voltages, we need to use multiple ADC channels. For example, when we need to build, an electrical energy meter, we need to measure both voltage and current. However, STM8S003K3 has one ADC which is multiplexed over four channels. This does not limit it from acquiring multiple analog signals and the job is easily achieved using ADC scan mode conversion.

In scan mode, the ADC automatically scans a sequence of channels from channel 0 to channel n, keeping the results of AD conversion in data buffer registers. At the end of conversion, the results are ready to be read.

Hardware Connection

adc_scan

Code Example

#include "STM8S.h"
#include "lcd.h"


unsigned char bl_state;
unsigned char data_value;


void clock_setup(void);
void GPIO_setup(void);
void ADC1_setup(void);
void lcd_print(unsigned char x_pos, unsigned char y_pos, unsigned int value);


void main()
{
       unsigned int A0 = 0x0000;
       unsigned int A1 = 0x0000;

       clock_setup();
       GPIO_setup();
       ADC1_setup();

       LCD_init(); 
       LCD_clear_home();

       LCD_goto(1, 0);
       LCD_putstr("STM8 Multi-ADC");
       LCD_goto(0, 1);
       LCD_putstr("A0");
       LCD_goto(9, 1);
       LCD_putstr("A1");

       while(TRUE)
       {
              ADC1_ScanModeCmd(ENABLE);
              ADC1_StartConversion();
              while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == FALSE);

              ADC1_ClearFlag(ADC1_FLAG_EOC);

              A0 = ADC1_GetBufferValue(0);
              A1 = ADC1_GetBufferValue(1);

              lcd_print(3, 1, A0);
              lcd_print(12, 1, A1);
              delay_ms(90);
       };
}


void clock_setup(void)
{
       CLK_DeInit();

       CLK_HSECmd(DISABLE);
       CLK_LSICmd(DISABLE);
       CLK_HSICmd(ENABLE);
       while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);

       CLK_ClockSwitchCmd(ENABLE);
       CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV4);
       CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

       CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
       DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

       CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE);
}


void GPIO_setup(void)
{
       GPIO_DeInit(GPIOB);
       GPIO_Init(GPIOB, ((GPIO_Pin_TypeDef)(GPIO_PIN_0 | GPIO_PIN_1)), GPIO_MODE_IN_FL_NO_IT);

       GPIO_DeInit(GPIOD);
       GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_OD_HIZ_FAST);
}


void ADC1_setup(void)
{
       ADC1_DeInit();     

       ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS,
                 ADC1_CHANNEL_0,
                 ADC1_PRESSEL_FCPU_D18,
                 ADC1_EXTTRIG_GPIO,
                 DISABLE,
                 ADC1_ALIGN_RIGHT,
                 ADC1_SCHMITTTRIG_CHANNEL0,
                 DISABLE);

       ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS,
                 ADC1_CHANNEL_1,
                 ADC1_PRESSEL_FCPU_D18,
                 ADC1_EXTTRIG_GPIO,
                 DISABLE,
                  ADC1_ALIGN_RIGHT,
                  ADC1_SCHMITTTRIG_CHANNEL1,
                  DISABLE);

       ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS,
                                                                                  ((ADC1_Channel_TypeDef)(ADC1_CHANNEL_0 | ADC1_CHANNEL_1)),
                                                                                  ADC1_ALIGN_RIGHT);

       ADC1_DataBufferCmd(ENABLE);
       ADC1_Cmd(ENABLE);
}


void lcd_print(unsigned char x_pos, unsigned char y_pos, unsigned int value)
{
       char chr = 0x00;

       chr = ((value / 1000) + 0x30);  
       LCD_goto(x_pos, y_pos);
       LCD_putchar(chr);

       chr = (((value / 100) % 10) + 0x30);
       LCD_goto((x_pos + 1), y_pos);
       LCD_putchar(chr);

       chr = (((value / 10) % 10) + 0x30);
       LCD_goto((x_pos + 2), y_pos);
       LCD_putchar(chr);

       chr = ((value % 10) + 0x30);
       LCD_goto((x_pos + 3), y_pos);
       LCD_putchar(chr);
}

 

Explanation

The setup here is same as the setup for the other ADC examples. There are a few difference though. Firstly, the channel configuration. Note that here two channels are used and are independently configured. This is so because each channel may have different properties. Secondly, conversion mode and data alignments are set. Thirdly, data buffers are enabled to capture ADC data on different channels.

void ADC1_setup(void)
{
       ADC1_DeInit();     

       ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS,
                 ADC1_CHANNEL_0,
                 ADC1_PRESSEL_FCPU_D18,
                 ADC1_EXTTRIG_GPIO,
                 DISABLE,
                 ADC1_ALIGN_RIGHT,
                 ADC1_SCHMITTTRIG_CHANNEL0,
                 DISABLE);

       ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS,
                 ADC1_CHANNEL_1,
                 ADC1_PRESSEL_FCPU_D18,
                 ADC1_EXTTRIG_GPIO,
                 DISABLE,
                 ADC1_ALIGN_RIGHT,
                 ADC1_SCHMITTTRIG_CHANNEL1,
                 DISABLE);

       ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS,
                                                                                  ((ADC1_Channel_TypeDef)(ADC1_CHANNEL_0 | ADC1_CHANNEL_1)),
                                                                                  ADC1_ALIGN_RIGHT);

       ADC1_DataBufferCmd(ENABLE);
       ADC1_Cmd(ENABLE);
}

Polling method is used to start and extract ADC data. Firstly, the ADC is told to do scan conversion. The conversion is then started. We, then, poll the end-of-conversion condition (EOC) status. EOC notifies that all ADC data have been captured and a scan has successfully completed. Finally, the EOC flag is cleared and the data are read from separate data buffers. Everytime a new scan is started the previous buffer data are cleared and are updated with new ones.

ADC1_ScanModeCmd(ENABLE);
ADC1_StartConversion();
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == FALSE);

ADC1_ClearFlag(ADC1_FLAG_EOC);

A0 = ADC1_GetBufferValue(0);
A1 = ADC1_GetBufferValue(1);

 

Demo

Scan Mode ADC (1) Scan Mode ADC (2)

Related Posts

12 comments

  • Hi,
    Thats great work
    Do you have steps for to work ST7735 TFT IN 8 BIT 8080 mode

  • I don’t even understand how I ended up right here, however
    I believed this publish used to be good. I don’t know who you are however definitely
    you’re going to a well-known blogger should you aren’t already.
    Cheers!

  • Sankalp Rai Gambhir

    Thanks Shawon, your blogs are indeed very helpful. Keep Growing.

  • why are you sending the received data back through TX pin?

  • Hi SHAWON SHAHRYIAR

    I am wondering how to get a Max31855 to talk to a STM8s via SPI.

    JP

    • What’s to wonder about it? It is a simple SPI communication and SPI for STM8 is no different from the SPI of other MCUs…. The following lines are taken from the device’s datasheet and the write up there states how to communicate with it:

      “Drive CS low to output the first bit on the SO pin. A complete serial-interface read of the cold-junction compensated thermocouple temperature requires 14 clock cycles. Thirty-two clock cycles are required to read both the thermocouple and reference junction temperatures (Table 2 and Table 3.) The first bit, D31, is the thermocouple temperature sign bit, and is presented to the SO pin within tDV of the falling edge of CS. Bits D[30:18] contain the converted temperature in the order of MSB to LSB, and are presented to the SO pin within tD0 of the falling edge of SCK. Bit D16 is normally low and goes high when the thermocouple input is open or shorted to GND or VCC. The reference junction temperature data begins with D15. CS can be taken high at any point while clocking out con-version data. If T+ and T- are unconnected, the thermocouple temperature sign bit (D31) is 0, and the remainder of the thermocouple temperature value (D[30:18]) is 1.”

Leave a Reply

Your email address will not be published. Required fields are marked *