Continuing the STM8 Expedition

STM8S105 Discovery

Low Power Sleep Mode

Low power sleep mode is a major requirement in any modern era microcontroller and that is because present-day modern gadgets use batteries as primary energy source. For instance, consider a smart watch like the Mikroelektronika’s HexiWear. Unlike previous generation of watches which used tiny LCDs and LED displays, this watch uses an OLED screen to project info. Most of the time we do not keep our eyes fixed at our watch and so it is unnecessary to keep the display powered up. Thus, it is a good idea to put the display and other unimportant functionalities of the watch to sleep. This suspended state in turn save limited battery energy to a great extent. The same trick can also be applied to STM8s.

HexiWear

There are a number of ways to reduce power consumption of a design. These include:

  • Using low frequency clocks.
  • Slowing down or switching to low speed clocks when fast processing is not needed.
  • Stopping or deinitializing unused hardware peripheral modules.
  • Using lower power supply voltages without compromising brownout limits.
  • Suspending the CPU until certain event(s) take place.
  • Avoiding polling-based or blocking codes.
  • Optimizing and organizing codes so that tasks are quickly and efficiently done.
  • Reducing design sizes and using SMD components.
  • Following recommended design notes and layout.

In terms of coding, including low power sleep mode in a code needs well-organized code planning. A developer must probe and formulate plans for both wakeup and sleep events. This is so because if a MCU goes to sleep then it must wake up upon fulfillment of certain event(s) or else it will appear to have got stuck in an unprecedented loop and will behave unresponsively. Similarly, it is wise to put it to sleep as much as possible in order to reduce power consumption. Thus, events like interrupts are very important in this regard.

 

Hardware Connection

Hardware

 

Code Example

 

#include "stm8s.h"


bool state = FALSE;


void GPIO_setup(void);
void EXTI_setup(void);
void clock_setup(void);


void main(void)
{
       unsigned char i = 0;

       GPIO_setup();
       EXTI_setup();
       clock_setup();

       for(i = 0; i <= 6; i++)
       {
              GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
              delay_ms(900);
       }
       wfi();

       while (TRUE)
       {
              for(i = 0; i < 4; i++)
              {
                     GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
                     delay_ms(600);
              }
              for(i = 0; i < 4; i++)
              {
                     GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
                     delay_ms(300);
              }
              halt();
       }
}


void GPIO_setup(void)
{
       GPIO_DeInit(GPIOB);   
       GPIO_Init(GPIOB, GPIO_PIN_7, GPIO_MODE_IN_PU_IT);

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


void EXTI_setup(void)
{
       ITC_DeInit();
       ITC_SetSoftwarePriority(ITC_IRQ_PORTB, ITC_PRIORITYLEVEL_0);

       EXTI_DeInit();
       EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB, EXTI_SENSITIVITY_FALL_ONLY);
       EXTI_SetTLISensitivity(EXTI_TLISENSITIVITY_FALL_ONLY);

       rim();
}


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_HSIDIV1);
       CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

       CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI,
       DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, 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);
}

 

Explanation

As the hardware connections suggest, Discovery board’s built-in LED and button are used. The button is set as an external interrupt source. In the main code shown below, all hardware and clock are set. When the board is powered, the built-in LED flashes slowly three times indicating the beginning of the application code. After the flashing has stopped, there is no other activity. This is because of the function

wfi() – Wait for Interrupt. When this function executes, the CPU is halted until an interrupt occurs. Here, the built-in button comes into play. It introduces the required interrupt. This interrupt causes the CPU to wake up and the CPU continues executing next instructions. Again, we’ll see fast variable rate flashes of the built-in LED and then no repetition of the same activity despite being in the main loop. This is because of the halt() function. This function also does the same thing as the wait for interrupt function. Thus, halt function also suspends CPU activities, reducing power consumption.

void main(void)
{
       unsigned char i = 0;

       GPIO_setup();
       EXTI_setup();
       clock_setup();

       for(i = 0; i <= 6; i++)
       {
              GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
              delay_ms(900);
       }
       wfi();

       while (TRUE)
       {
              for(i = 0; i < 4; i++)
              {
                     GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
                     delay_ms(600);
              }
              for(i = 0; i < 4; i++)
              {
                     GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
                     delay_ms(300);
              }
              halt();
       }
}

 

Demo

WFI (1) WFI (2)

Related Posts

8 comments

  • 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 *