Continuing the STM8 Expedition

STM8S105 Discovery

UART Interrupt

We have seen that we can use UART without interrupt methods. However, in most cases, UART interrupts are needed to make a serial communication real-time. In particular UART reception interrupt is of great importance. For example, when it is needed to interface a serial GPS receiver with a host micro, we will need UART reception interrupt because the GPS receiver will be continuously sending GPS data and it will be unwise to poll UART. If reception interrupt is used, the host micro will then be continually receiving GPS data in the background while doing other tasks in the main foreground.

Hardware Connection

uart

Code Example

 

stm8s_it.h (top part only)

#ifndef __STM8S_IT_H
#define __STM8S_IT_H

@far @interrupt void UART_RX_IRQHandler(void);

/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
....

 

stm8s_it.c (top part only)

#include "stm8s.h"
#include "stm8s_it.h"


extern unsigned char pos;
extern unsigned char RX_value[16];


void UART_RX_IRQHandler(void)
{
       RX_value[pos] = UART1_ReceiveData8();
       UART1_ClearITPendingBit(UART1_IT_RXNE);
       UART1_ClearFlag(UART1_FLAG_RXNE);

       UART1_SendData8(RX_value[pos]);
       UART1_ClearFlag(UART1_FLAG_TXE);

       pos++;

       if(pos > 15)
       {
              pos = 0;
       }
}
....

 

stm8_interrupt_vector.c (shortened)

#include "stm8s_it.h"


typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
       unsigned char interrupt_instruction;
       interrupt_handler_t interrupt_handler;
};

//@far @interrupt void NonHandledInterrupt (void)
//{
       /* in order to detect unexpected events during development,
          it is recommended to set a breakpoint on the following instruction
       */
//     return;
//}

extern void _stext();     /* startup routine */

struct interrupt_vector const _vectab[] = {
       {0x82, (interrupt_handler_t)_stext}, /* reset */
       {0x82, NonHandledInterrupt}, /* trap  */
       {0x82, NonHandledInterrupt}, /* irq0  */
       ....
       {0x82, (interrupt_handler_t)UART_RX_IRQHandler}, /* irq18 */
       ....
       {0x82, NonHandledInterrupt}, /* irq29 */
};

 

main.c

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


unsigned char pos;
unsigned char bl_state;
unsigned char RX_value[16];
unsigned char data_value;


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


void main(void)
{
       clock_setup();
       GPIO_setup();
       UART1_setup();

       LCD_init(); 
       LCD_clear_home();

       LCD_goto(1, 0);
       LCD_putstr("STM8S UART ISR");

       while(TRUE)
       {
              LCD_goto(0, 1);
              LCD_putstr(RX_value);
              delay_ms(100);
       };
}


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_UART1, ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, 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(GPIOD);
       GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_OD_HIZ_FAST);
       GPIO_Init(GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_FAST);
       GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_IN_FL_NO_IT);
}


void UART1_setup(void)
{
       UART1_DeInit();

       UART1_Init(9600,
                  UART1_WORDLENGTH_8D,
                  UART1_STOPBITS_1,
                  UART1_PARITY_NO,
                  UART1_SYNCMODE_CLOCK_DISABLE,
                  UART1_MODE_TXRX_ENABLE);

       UART1_ITConfig(UART1_IT_RXNE, ENABLE);
       enableInterrupts();

       UART1_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 UART setup is same as before. The exception is the interrupt part:

UART1_ITConfig(UART1_IT_RXNE, ENABLE);
enableInterrupts();

These lines enable UART reception interrupt and global interrupt.

Just as with other interrupts, UART reception interrupt is enabled in the STM8S interrupt vector map file.

{0x82, (interrupt_handler_t)UART_RX_IRQHandler}, /* irq18 */

When a valid UART data is received by the UART RX pin, an UART reception interrupt is triggered. UART buffer is read. UART reception pending bit and reception flag are both cleared to pave way for further receptions. The data received is stored in an array for displaying it later and is immediately transmitted back through UART TX pin.

In the STM8 interrupt source file the following lines of code are added to do all these tasks:

void UART_RX_IRQHandler(void)
{
       RX_value[pos] = UART1_ReceiveData8();
       UART1_ClearITPendingBit(UART1_IT_RXNE);
       UART1_ClearFlag(UART1_FLAG_RXNE);

 

       UART1_SendData8(RX_value[pos]);
       UART1_ClearFlag(UART1_FLAG_TXE);

 

       pos++;

 

       if(pos > 15)
       {
              pos = 0;
       }
}

 

Demo

UART ISR

Continue Reading ...

Related Posts

23 comments

  • Ϝirst ᧐f aⅼl I would ⅼike tօ say awesome blog!
    Ι had а quick question tһɑt I’ɗ ⅼike to aѕk
    іf yoᥙ don’t mind. Ӏ was curious to knoᴡ how you center yourself ɑnd clear yοur thoսghts prior to writing.
    Ӏ’ѵе had difficulty clearing mү mind in getting mу ideas out tһere.
    I tгuly do tɑke pleasure in writing howeᴠer
    іt just ѕeems lіke tһe first 10 to 15 minutes tend to be lost simply ϳust trʏing to figure օut һow to begin. Any ideas or hints?
    Kudos!

    • Well firstly, to me the concepts of all microcontrollers in world is same and so provided that you have some degree of knowledge of internal peripherals, you can unlock anyone of them by systematically trying out each peripheral on your own…. Secondly, how to start is up to you…. When I compose a blog and plan what I would be focusing on, I take things as such that my audience is in front of me and would likely to ask me the very basics…. I try to write things in simplest possible language and with minimum word count while highlighting what is most important…. A blog on any microcontroller should focus on every aspect and not just a few topics…. Lastly, planning and persistently going by the plan to achieve a vision will surely bring out a good result…. Just don’t lose focus and don’t let yourself be pressurized by too many unknown variables….

  • It’s not my first time to ѵisіt thіѕ web page, i am visiting this webѕite
    dailly and obtain pleasɑnt information from herе
    all the time.

  • I visited multiple blogs except tһe audio quality f᧐r audio songs existing аt this web paɡe iѕ tгuly superb.

  • Dear Shawon,
    Thank you for your useful website and articles.
    I have taken a look at ADC1_Init definition and I found it uses ADC1_ConversionConfig to set channels and conversion mode. So it seems using ADC1_Init once with all needed channels is enough. Am I right?
    Thank you very much.

  • Hello,
    I am learning stm8s, but i have a project in my mind, i am making Pong game with two encoders and PCD8544 LCD. Your tutorials are great and it’s very big source of knowledge for me, and i have a question about this article:
    Is it possible to use two encoder this way? Or can it be done in the other way? I have stm8s103f3p6, and i know it has 4 interrupt pins, so I thought about using these for two encoders, but then i saw your article about QEI

  • Hello Friend!!
    Your stuff is great !!!
    Would you have an example 433 mhz rf signal capture with flash code writing?

  • Ola amigo !!!
    Seu material é excelente!
    Você teria algum exemplo de captura de sinal rf 433 mhz com gravação na flash?

  • Hello friends, pleasant paragraph ɑnd good urging commented ɑt tһiѕ ρlace,
    I ɑm truⅼy enjoying ƅy tһese.

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