STM8 Relay board control

We will use the 1$ board – equipped with a STM8S103F3 micro-controller from ST – in order to develop a control unit for a relay board. The board will be used in our Surveillance platform as watchdog mechanism, so in case that the software detects a malfunction on an external device that can not be recovered using software methods – then a command for restarting the device will be send. This is needed because it has been noticed that some devices – such as DSL router/modem – loose communication after certain condition (ie lightnings can affect the normal operation for devices connected to land line telephony interface). In addition, a watchdog mechanism will be implement. The user will be able to trigger a watchdog, defining the timeout value. If no update message received within this time , the the output will be triggered – resetting the attached device.

we are using the minimal development board design of STM8 for our project:

stm8

For programming our module we will use the ST-LINK V2 USB programmer:

st-linkST-LINK programmers are fully supported by the open source stm8flash tool and sdcc compiler for small devices that also supports STM8 devices. We can easily install all the required tools – under linux – by executing the following apt command:

> sudo apt-get install sdcc
> cd /opt
> sudo git clone https://github.com/johnkok/stm8flash.git
> make
> sudo make install

Now we are ready to develop our application and program the STM8 device. We are going to use the UART1 channel, which is the only UART channel provided in our board, for communicating with our server, four bits of port C for triggering the relay board channels and also a timer for decreasing the watchdog timeout values.

stm8_rel

The board is communicating through the UART channel at 9600bps – 1 stop bit – no parity. The control packet consists by 4 bytes: a preamble (0xAE), the channel number (0 to 3 in our case), the time value (0: switch off, 255: disable, 1-254: watchdog time value) and finally a checksum byte – summing the three previous bytes.

#include <stdint.h>
#include <stdio.h>
#include "stm8l.h"

#define CHANNELS 4
#define DATA_SIZE 4
#define rim()  {__asm__("rim\n");}  /* enable interrupts */
#define sim()  {__asm__("sim\n");}  /* disable interrupts */

unsigned char Times[CHANNELS] = {0xff,0xff,0xff,0xff};
unsigned char RxBuffer[4]; 
unsigned char RxPtr = 0;

void UART1_RX_IRQHandler (void) __interrupt(18){
   unsigned char rx = USART1_DR;

   if (RxPtr == 0){ 
      if (rx == 0xAE){
         RxBuffer[RxPtr] = rx;
         RxPtr++;
      }
   }else{
      RxBuffer[RxPtr] = rx;
      RxPtr++;
      if (RxPtr >= DATA_SIZE){
         if((RxBuffer[DATA_SIZE-1] == (RxBuffer[0] + RxBuffer[1] + RxBuffer[2])) && 
             ( RxBuffer[1] < CHANNELS )){
                Times[RxBuffer[1]] = RxBuffer[2];
         }
         RxPtr = 0;
      }
   }
}

void putchar(char c)
{
    while(!(USART1_SR & USART_SR_TXE));
	USART1_DR = c;
}

void InitialiseUART()
{
    unsigned char flush = USART1_SR;
    flush = USART1_DR;

    USART1_BRR2 = 0x00;  //  Set the baud rate registers to 9600 baud
    USART1_BRR1 = 0x0d;  //  based upon a 16 MHz system clock.
    USART1_CR3 &= ~(USART_CR3_STOP1 | USART_CR3_STOP2); //1-stop bit
    USART1_CR2 = USART_CR2_TEN | USART_CR2_REN | USART_CR2_RIEN; //Enable Rx Tx
}

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

        // Set internal clock generator
	CLK_DIVR = 0x00; 
	CLK_PCKENR1 = 0xFF;

        // Initialize output port
        PC_ODR = 0xFF;
	PC_DDR = 0x08 | 0x10 | 0x20 | 0x40;
	PC_CR1 = 0x08 | 0x10 | 0x20 | 0x40;

	InitialiseUART();

	rim();

	for(;;){
		printf("1:%d\n\r2:%d\n\r3:%d\n\r4:%d\n\r",
			Times[0],Times[1],Times[2],Times[3]);
		for(i = 0; i < 200000 ; i++); // Sleep

		output=0;
                for (i = 0 ; i < CHANNELS ; i++){
                    if (Times[i] != 0xFF){ // not disabled
                        Times[i]--; 
                    }     
	    	    if(Times[i]){
 		       output += 8<<i;
 		    }
                }
                PC_ODR = output;  
	}
}

We can compile our application and flash our board:

> sdcc -mstm8 --opt-code-size -Wl-bHOME=0x8000 --std-c99 watchdog.c 
> sudo stm8flash -c stlinkv2 -p stm8s103?3 -w watchdog.ihx

Finally, we have to set the script checking for devices connection and set watchdog times:

#!/bin/bash

function set_channel {

CHANNEL=$1
TIME=$2
CRC=$(((CHANNEL + TIME + 0xAE)%256))

printf -v CHANNEL_HEX "%x" "$CHANNEL"
printf -v TIME_HEX "%x"    "$TIME"
printf -v CRC_HEX "%x"     "$CRC"

   /bin/echo -en "\xAE" > $WD_DEV
   sleep $CMD_DEL
   /bin/echo -en "\x${CHANNEL_HEX}" > $WD_DEV
   sleep $CMD_DEL
   /bin/echo -en "\x${TIME_HEX}" > $WD_DEV
   sleep $CMD_DEL
   /bin/echo -en "\x${CRC_HEX}" > $WD_DEV
   sleep $CMD_DEL

}

###########################################

WD_DEV="/dev/ttyUSB0"
CMD_DEL=0.01

chmod 777 $WD_DEV

# Set server watchdog
set_channel 0 240

# Check router connection
ROUTER=`ping -c 1 192.168.1.1 | grep "1 received"`
if [ "$ROUTER" != "" ]
then
   set_channel 1 30
fi

# Check internet connection
INTERNET=`ping -c 1 www.google.com | grep "1 received"`
if [ "$INTERNET" != "" ]
then
   set_channel 2 240
fi