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

2 comments

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