├── LICENSE ├── Makefile ├── README.md ├── aes_stm8.c ├── aes_stm8.h ├── aes_tables.c ├── aes_tables.h ├── lib_adc.c ├── lib_adc.h ├── lib_bindec.c ├── lib_bindec.h ├── lib_board.c ├── lib_board.h ├── lib_cap2.c ├── lib_cap2.h ├── lib_cli.c ├── lib_cli.h ├── lib_clock.c ├── lib_clock.h ├── lib_delay.c ├── lib_delay.h ├── lib_eeprom.c ├── lib_eeprom.h ├── lib_flash.c ├── lib_flash.h ├── lib_i2c.c ├── lib_i2c.h ├── lib_keypad.c ├── lib_keypad.h ├── lib_lcd.c ├── lib_lcd.h ├── lib_log.c ├── lib_log.h ├── lib_m9800.c ├── lib_m9800.h ├── lib_max6675.c ├── lib_max6675.h ├── lib_max7219.c ├── lib_max7219.font ├── lib_max7219.h ├── lib_ping.c ├── lib_ping.h ├── lib_pins.h ├── lib_pwm.c ├── lib_pwm.h ├── lib_rotary.c ├── lib_rotary.h ├── lib_spi.c ├── lib_spi.h ├── lib_stm8.lib ├── lib_tim4.c ├── lib_tim4.h ├── lib_tm1637.c ├── lib_tm1637.h ├── lib_tm1638.c ├── lib_tm1638.h ├── lib_uart.c ├── lib_uart.h ├── lib_w1209.c ├── lib_w1209.h ├── stm8_103.h ├── stm8_103.inc ├── stm8_105.h ├── stm8_105.inc ├── stm8s_003.h ├── stm8s_003.inc ├── stm8s_207.h ├── stm8s_header.h └── vectors.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2008, 2009 Richard Hodges 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = cc -Wall -O2 2 | SDCC = sdcc -mstm8 -DSTM8103 3 | SDAR = sdar 4 | NAME = lib_stm8 5 | OBJS = lib_bindec.rel lib_rotary.rel lib_uart.rel lib_lcd.rel\ 6 | aes_stm8.rel lib_cap2.rel lib_max7219.rel lib_cli.rel\ 7 | lib_clock.rel lib_log.rel lib_i2c.rel lib_m9800.rel lib_tm1638.rel \ 8 | lib_pwm.rel lib_eeprom.rel lib_adc.rel lib_keypad.rel lib_flash.rel \ 9 | lib_delay.rel lib_ping.rel lib_tm1637.rel lib_w1209.rel \ 10 | lib_board.rel lib_spi.rel lib_tim4.rel lib_max6675.rel 11 | 12 | .SUFFIXES : .rel .c 13 | 14 | all: $(NAME).lib 15 | 16 | $(NAME).lib: $(OBJS) 17 | $(SDAR) rc $(NAME).lib $? 18 | 19 | .c.rel : 20 | $(SDCC) -c $< 21 | 22 | clean: 23 | - rm -f *.adb *.asm *.cdb *.ihx *.lk *.lst *.map *.rel *.rst *.sym \ 24 | aes_tables aes_tables.h 25 | 26 | aes_stm8.rel: aes_stm8.c aes_tables.h 27 | $(SDCC) -c aes_stm8.c 28 | 29 | aes_tables: aes_tables.c 30 | $(CC) -o aes_tables aes_tables.c 31 | 32 | aes_tables.h: aes_tables 33 | ./aes_tables > aes_tables.h 34 | 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stm8_libs 2 | Library collection for STM8, specifically stm8s103 and stm8s105. 3 | My personal web pages are older and do not cover everything here, 4 | but there are some nice pictures and links to buy cheap parts on eBay: 5 | http://www.hodges.org/rh/stm8 6 | 7 | My intent is to have a good working set of libraries to simplify the use of 8 | internal peripherals (eg, UART1), give easier control (eg, PWM and servo 9 | control), and support external devices more easily (eg, LCD & LED displays, 10 | keypads, rotary encoders.) 11 | 12 | The wiki pages document the functions in these libraries: 13 | https://github.com/unfrozen/stm8_libs/wiki 14 | 15 | I want each function to be as small as possible, so that even the stm8s103, 16 | with only 8k of program memory, can do great things. Where it makes sense, 17 | I use inline assembly to save bytes or when the C code is too ugly 18 | (eg, bit operations). Once the code is debuggged, it can be used by anyone. 19 | (I think using inline assembly in main code is a BAD IDEA.) 20 | 21 | This code uses the SDCC compiler. Some of the libraries need to know which 22 | CPU you are using, so please use -DSTM8103 or -DSTM8105 in the Makefile. 23 | 24 | I am available for embedded projects of any size. You can contact me at: 25 | richard@hodges.org 26 | 27 | -------------------------------------------------------------------------------- /aes_stm8.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Program: aes_stm8.h 3 | * 4 | * Date first: 12/17/2017 5 | * Date last: 12/17/2017 6 | * 7 | * Author: Richard Hodges 8 | * 9 | * This is a library for encoding and decoding AES 128 blocks on STM8. 10 | * 11 | ****************************************************************************** 12 | * 13 | * Copyright (C) 2017 Richard Hodges. All rights reserved. 14 | * Permission is hereby granted for any use. 15 | * 16 | ****************************************************************************** 17 | * 18 | * Types 19 | */ 20 | 21 | #ifndef _BYTE 22 | #define _BYTE 23 | typedef unsigned char BYTE; 24 | #endif 25 | 26 | typedef struct { 27 | BYTE *block; 28 | BYTE key[11][16]; 29 | unsigned char round; 30 | } AES_CTX; 31 | 32 | void aes_new_key(AES_CTX *, BYTE *); 33 | void aes_encrypt(AES_CTX *, BYTE *); 34 | void aes_decrypt(AES_CTX *, BYTE *); 35 | 36 | -------------------------------------------------------------------------------- /aes_tables.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: aes_tables.c 3 | * Date first: 12/13/2017 4 | * Date last: 12/13/2017 5 | * 6 | * Description: Output AES mix tables. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, Richard Hodges. All rights reserved. 11 | * Permission is granted to use or copy for any purpose. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Includes 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /****************************************************************************** 24 | * 25 | * Types 26 | */ 27 | 28 | #ifndef _BYTE 29 | #define _BYTE 30 | typedef unsigned char BYTE; 31 | #endif 32 | 33 | 34 | static BYTE mix_mul2(BYTE); 35 | static void print_table(char *, BYTE *); 36 | 37 | /****************************************************************************** 38 | * 39 | */ 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | BYTE x_2[256]; 44 | BYTE x_3[256]; 45 | BYTE x_9[256]; 46 | BYTE x_11[256]; 47 | BYTE x_13[256]; 48 | BYTE x_14[256]; 49 | int i, val; 50 | 51 | for (i = 0; i < 256; i++) { 52 | val = i; 53 | x_3[i] = val; /* x 1 */ 54 | x_9[i] = val; 55 | x_11[i] = val; 56 | x_13[i] = val; 57 | val = mix_mul2(val); /* x 2 */ 58 | x_2[i] = val; 59 | x_3[i] ^= val; 60 | x_11[i] ^= val; 61 | x_14[i] = val; 62 | val = mix_mul2(val); /* x 4 */ 63 | x_13[i] ^= val; 64 | x_14[i] ^= val; 65 | val = mix_mul2(val); /* x 8 */ 66 | x_9[i] ^= val; 67 | x_11[i] ^= val; 68 | x_13[i] ^= val; 69 | x_14[i] ^= val; 70 | } 71 | print_table("mix_2", x_2); 72 | print_table("mix_3", x_3); 73 | print_table("mix_9", x_9); 74 | print_table("mix_11", x_11); 75 | print_table("mix_13", x_13); 76 | print_table("mix_14", x_14); 77 | 78 | return 0; 79 | } 80 | 81 | /****************************************************************************** 82 | * 83 | * Print mix table 84 | */ 85 | 86 | static void print_table(char *tabname, BYTE *table) 87 | { 88 | int i, j; 89 | 90 | printf("const BYTE %s[256] = {", tabname); 91 | for (i = 0; i < 32; i++) { 92 | printf("\n "); 93 | for (j = 0; j < 8; j++) 94 | printf("0x%02x, ", *table++); 95 | } 96 | printf("\n};\n"); 97 | } 98 | 99 | /****************************************************************************** 100 | * 101 | * Multiply by two for mix operation 102 | */ 103 | 104 | static BYTE mix_mul2(BYTE val) 105 | { 106 | BYTE retval; 107 | 108 | retval = val << 1; 109 | if (val & 0x80) 110 | retval ^= 0x1b; 111 | 112 | return (retval); 113 | } 114 | -------------------------------------------------------------------------------- /lib_adc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_adc.c 3 | * Date first: 09/14/2018 4 | * Date last: 09/15/2018 5 | * 6 | * Description: Library for using STM8S ADC. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | #include "stm8s_header.h" 17 | 18 | #include "lib_adc.h" 19 | 20 | #ifdef STM8103 21 | #define CR1_VAL 0x21 /* 16mhz / 4 = 4mhz ADC */ 22 | #endif 23 | #ifdef STM8105 24 | #define CR1_VAL 0x01 /* 8mhz / 2 = 4mhz ADC */ 25 | #endif 26 | 27 | /****************************************************************************** 28 | * 29 | * Initialize 30 | * in: bits for ADC channel(s) to use 31 | * (Note that this may be called from multiple sub-systems) 32 | */ 33 | 34 | void adc_init(char chans) 35 | { 36 | #ifdef ORIG_C 37 | ADC_TDRL |= chans & ADC_MASK; /* disable schmitt triggers for analog */ 38 | if (chans & ADC_CH12) 39 | ADC_TDRH |= 0x10; 40 | ADC_CR2 = 0x08; /* result is right aligned */ 41 | ADC_CR1 = CR1_VAL; /* enable ADC */ 42 | #else 43 | chans; 44 | __asm 45 | ld a, (3, sp) 46 | and a, #ADC_MASK 47 | ldw x, #_ADC_TDRL 48 | or a, (x) 49 | ld (x), a 50 | 51 | ld a, (3, sp) 52 | and a, #ADC_CH12 53 | jreq 00001$ 54 | bset _ADC_TDRH, #4 55 | 00001$: 56 | mov _ADC_CR2, #0x08 57 | mov _ADC_CR1, #CR1_VAL 58 | __endasm; 59 | #endif 60 | } 61 | 62 | /****************************************************************************** 63 | * 64 | * Get average of 4 A/D samples 65 | * in: ADC channel (0 to 12) 66 | * out: 10-bit A/D average value, -1 if timeout 67 | */ 68 | short adc_avg(char chan) 69 | { 70 | #ifdef ORIG_C 71 | short avg, val; 72 | char i; 73 | 74 | avg = 2; 75 | for (i = 0; i < 4; i++) { 76 | val = adc_val(chan); 77 | if (val < 0) 78 | return -1; 79 | avg += val; 80 | } 81 | return avg >> 2; 82 | #else 83 | #pragma disable_warning 59 84 | chan; 85 | __asm 86 | ldw x, #2 87 | pushw x 88 | push #4 89 | 00001$: 90 | ld a, (6, sp) 91 | push a 92 | call _adc_val 93 | pop a 94 | tnzw x 95 | jrmi 000090$ 96 | addw x, (2, sp) 97 | ldw (2, sp), x 98 | dec (1, sp) 99 | jrne 00001$ 100 | 101 | srlw x 102 | srlw x 103 | 00090$: 104 | add sp, #3 105 | __endasm; 106 | #endif 107 | } 108 | 109 | /****************************************************************************** 110 | * 111 | * Get current raw A/D value 112 | * in: ADC channel (0 to 12) 113 | * out: 10-bit A/D conversion value, -1 if timeout 114 | */ 115 | #pragma disable_warning 59 116 | 117 | short adc_val(char chan) 118 | { 119 | chan; 120 | __asm 121 | bres _ADC_CSR, #7 ; clear end of conversion flag 122 | ld a, (3, sp) 123 | ld _ADC_CSR, a ; set A/D channel 124 | bset _ADC_CR1, #0 ; start conversion 125 | 126 | ld a, #100 ; conversion is 3.5 uS, 56 cycles @ 16mhz 127 | 00001$: 128 | btjt _ADC_CSR, #7, 00090$ ; (2) 129 | dec a ; (1) 130 | jrne 00001$ ; (2) = 5 per loop, should be done < 12 131 | clrw x 132 | decw x 133 | ret 134 | 00090$: 135 | ld a, _ADC_DRL ; (24.11.8) read DRL first with right-justify 136 | ld xl, a 137 | ld a, _ADC_DRH 138 | ld xh, a 139 | __endasm; 140 | } 141 | -------------------------------------------------------------------------------- /lib_adc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_adc.h 3 | * Date first: 09/14/2018 4 | * Date last: 10/11/2018 5 | * 6 | * Description: Library for using STM8S ADC. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize 16 | * in: bits for ADC channel(s) to use 17 | */ 18 | void adc_init(char); 19 | 20 | /* Pin numbers are for 103F SO20 and 105K LQFP32 */ 21 | 22 | #define ADC_CH0 0x01 /* B0: 16 */ 23 | #define ADC_CH1 0x02 /* B1: 15 */ 24 | #define ADC_CH2 0x04 /* C4: 14 B2: 14 */ 25 | #define ADC_CH3 0x08 /* D2: 19 B3: 13 */ 26 | #define ADC_CH4 0x10 /* D3: 20 B4: 12 */ 27 | #define ADC_CH5 0x20 /* D5: 2 B5: 11 */ 28 | #define ADC_CH6 0x40 /* D6: 3 */ 29 | #define ADC_CH12 0x80 /* F4: 8 */ 30 | #define ADC_MASK 0x7f 31 | 32 | /* 33 | * Get current raw A/D value 34 | * in: ADC channel (0 to 12) 35 | * out: 10-bit A/D conversion value, -1 if timeout 36 | */ 37 | short adc_val(char); 38 | 39 | /* 40 | * Get average of 4 A/D samples 41 | * in: ADC channel (0 to 12) 42 | * out: 10-bit A/D average value, -1 if timeout 43 | */ 44 | short adc_avg(char); 45 | -------------------------------------------------------------------------------- /lib_bindec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_bindec.c 3 | * Date first: 12/22/2017 4 | * Date last: 09/13/2022 5 | * 6 | * Description: Library of binary/decimal functions for STM8 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018, 2022 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * SDCC and COSMIC have different calling conventions. 16 | * Define SDCC here or in the Makefile, COSMIC defaults otherwise. 17 | */ 18 | 19 | #ifndef __SDCC 20 | #define COSMIC 21 | #endif 22 | 23 | /****************************************************************************** 24 | * 25 | * Binary to decimal, terminate with zero 26 | * 27 | * in: binary (16 bits), 5 char buffer 28 | */ 29 | 30 | void bin16_dec(short bin, char *dec) 31 | { 32 | bin, dec; 33 | 34 | #ifdef __SDCC 35 | __asm 36 | #if __SDCCCALL == 0 37 | ldw x, (3, sp) 38 | #endif 39 | #endif 40 | #ifdef COSMIC 41 | #asm /* binary provided in X */ 42 | #endif 43 | sub sp, #4 44 | 45 | ldw y, #10000 46 | divw x, y 47 | ld a, xl 48 | add a, #'0' 49 | ld (1, sp), a 50 | 51 | ldw x, #1000 52 | exgw x, y 53 | divw x, y 54 | ld a, xl 55 | add a, #'0' 56 | ld (2, sp), a 57 | 58 | ldw x, #100 59 | exgw x, y 60 | divw x, y 61 | ld a, xl 62 | add a, #'0' 63 | ld (3, sp), a 64 | 65 | ldw x, #10 66 | exgw x, y 67 | divw x, y 68 | ld a, xl 69 | add a, #'0' 70 | ld (4, sp), a 71 | 72 | ld a, yl 73 | add a, #'0' 74 | #ifdef __SDCC 75 | #if __SDCCCALL == 0 76 | ldw x, (9, sp) /* decimal buffer */ 77 | #else 78 | ldw x, (7, sp) 79 | #endif 80 | #endif 81 | #ifdef COSMIC 82 | ldw x, (10, sp) 83 | #endif 84 | ld (4, x), a 85 | ldw y, (1, sp) 86 | ldw (0, x), y 87 | ldw y, (3, sp) 88 | ldw (2, x), y 89 | 90 | clr (5, x) 91 | add sp, #4 92 | #ifdef __SDCC 93 | __endasm; 94 | #endif 95 | #ifdef COSMIC 96 | #endasm 97 | #endif 98 | } 99 | 100 | /****************************************************************************** 101 | * 102 | * Binary to decimal, terminate with zero 103 | * 104 | * in: binary (32 bits), 10 char buffer 105 | */ 106 | 107 | void bin32_dec(long bin, char *dec) 108 | { 109 | bin, dec; 110 | 111 | #ifdef __SDCC 112 | __asm 113 | ldw x, (7, sp) ; decimal buffer pointer 114 | ldw y, sp 115 | addw y, #3 ; 32 bit binary on stack 116 | 117 | clr (x) ; zero the BCD area 118 | clr (1, x) 119 | clr (2, x) 120 | clr (3, x) 121 | clr (4, x) 122 | 123 | sub sp, #2 124 | ld a, #32 125 | ld (1, sp), a 126 | 127 | 00001$: 128 | ld a, #5 129 | ld (2, sp), a 130 | 131 | 00002$: 132 | ld a, #0x33 ; assume DAA is needed 133 | add a, (x) 134 | jrmi 00003$ ; N set if nybble was 5-9 135 | sub a, #0x30 ; nybble was 0-4, so undo DAA 136 | 00003$: 137 | add a, #8 ; push bit-3 into HC 138 | jrh 00004$ 139 | sub a, #3 ; undo DAA 140 | 00004$: 141 | sub a, #8 ; undo add #8 above 142 | ld (x), a 143 | 144 | incw x 145 | dec (2, sp) 146 | jrne 00002$ 147 | subw x, #5 148 | 149 | rlc (3, y) ; rotate 32 bit binary into BCD 150 | rlc (2, y) 151 | rlc (1, y) 152 | rlc (y) 153 | rlc (4, x) 154 | rlc (3, x) 155 | rlc (2, x) 156 | rlc (1, x) 157 | rlc (x) 158 | 159 | dec (1, sp) 160 | jrne 00001$ 161 | 162 | ldw y, x 163 | addw y, #9 164 | addw x, #4 165 | 166 | ld a, #5 167 | ld (1, sp), a 168 | 00005$: 169 | ld a, (x) 170 | and a, #0x0f 171 | add a, #'0' 172 | ld (y), a 173 | decw y 174 | 175 | ld a, (x) 176 | swap a 177 | and a, #0x0f 178 | add a, #'0' 179 | ld (y), a 180 | decw y 181 | decw x 182 | 183 | dec (1, sp) 184 | jrne 00005$ 185 | 186 | clr (11, y) 187 | add sp, #2 188 | 189 | __endasm; 190 | #endif /* SDCC */ 191 | 192 | #ifdef COSMIC 193 | #asm 194 | ldw x, (8, sp) ; decimal buffer pointer 195 | ldw y, sp 196 | addw y, #4 ; 32 bit binary on stack 197 | 198 | clr (x) ; zero the BCD area 199 | clr (1, x) 200 | clr (2, x) 201 | clr (3, x) 202 | clr (4, x) 203 | 204 | sub sp, #2 205 | ld a, #32 206 | ld (1, sp), a 207 | 208 | bit_loop: 209 | ld a, #5 210 | ld (2, sp), a 211 | 212 | bcd_loop: 213 | ld a, #0x33 ; assume DAA is needed 214 | add a, (x) 215 | jrmi daa_h ; N set if nybble was 5-9 216 | sub a, #0x30 ; nybble was 0-4, so undo DAA 217 | daa_h: 218 | add a, #8 ; push bit-3 into HC 219 | jrh daa_l 220 | sub a, #3 ; undo DAA 221 | daa_l: 222 | sub a, #8 ; undo add #8 above 223 | ld (x), a 224 | 225 | incw x 226 | dec (2, sp) 227 | jrne bcd_loop 228 | subw x, #5 229 | 230 | rlc (3, y) ; rotate 32 bit binary into BCD 231 | rlc (2, y) 232 | rlc (1, y) 233 | rlc (y) 234 | rlc (4, x) 235 | rlc (3, x) 236 | rlc (2, x) 237 | rlc (1, x) 238 | rlc (x) 239 | 240 | dec (1, sp) 241 | jrne bit_loop 242 | 243 | ldw y, x 244 | addw y, #9 245 | addw x, #4 246 | 247 | ld a, #5 248 | ld (1, sp), a 249 | ascii_loop: 250 | ld a, (x) 251 | and a, #0x0f 252 | add a, #'0' 253 | ld (y), a 254 | decw y 255 | 256 | ld a, (x) 257 | swap a 258 | and a, #0x0f 259 | add a, #'0' 260 | ld (y), a 261 | decw y 262 | decw x 263 | 264 | dec (1, sp) 265 | jrne ascii_loop 266 | 267 | clr (11, y) 268 | add sp, #2 269 | #endasm 270 | #endif /* COSMIC */ 271 | } 272 | 273 | /****************************************************************************** 274 | * 275 | * Trim leading zeroes from decimal buffer 276 | * in: buffer, maximum zeroes to remove 277 | * out: first non-zero digit 278 | */ 279 | 280 | char *decimal_rlz(char *buf, char max) 281 | { 282 | while (max) { 283 | if (*buf != '0') 284 | break; 285 | *buf = ' '; 286 | buf++; 287 | max--; 288 | } 289 | return buf; 290 | } 291 | 292 | /****************************************************************************** 293 | * 294 | * * Combine 16 bit binary to decimal and remove leading zeroes 295 | * in: 16 bit binary, 6 digit buffer 296 | * out: first non-zero digit 297 | */ 298 | 299 | char *bin16_dec_rlz(short bin, char *dec) 300 | { 301 | bin16_dec(bin, dec); 302 | return decimal_rlz(dec, 4); 303 | } 304 | 305 | /****************************************************************************** 306 | * 307 | * Convert 8 bit unsigned binary to 2 digit decimal, terminate with zero 308 | */ 309 | 310 | void bin8_dec2(char bin, char *dec) 311 | { 312 | bin, dec; 313 | __asm 314 | #if __SDCCCALL == 0 315 | ld a, (3, sp) 316 | ldw y, (4, sp) 317 | #else 318 | ldw y, x 319 | #endif 320 | clrw x 321 | ld xl, a 322 | 323 | ld a, #100 324 | div x, a 325 | exg a, xl 326 | 327 | ld a, #10 328 | div x, a 329 | or a, #'0' 330 | ld (1, y), a 331 | exg a, xl 332 | or a, #'0' 333 | ld (y), a 334 | 335 | clr (2, y) 336 | __endasm; 337 | } 338 | 339 | /****************************************************************************** 340 | * 341 | * Convert binary byte to hex, terminate with zero 342 | * in: binary, buffer 343 | */ 344 | 345 | void bin8_hex(char val, char *hex) 346 | { 347 | #ifdef __SDCC 348 | val, hex; 349 | __asm 350 | #if __SDCCCALL == 0 351 | ldw x, (4, sp) 352 | ld a, (3, sp) 353 | #else 354 | push a 355 | #endif 356 | swap a 357 | and a, #0x0f 358 | add a, #6 359 | jrh 00001$ 360 | sub a, #7 361 | 00001$: 362 | add a, #'0'+1 363 | ld (x), a 364 | #if __SDCCCALL == 0 365 | ld a, (3, sp) 366 | #else 367 | pop a 368 | #endif 369 | and a, #0x0f 370 | add a, #6 371 | jrh 00002$ 372 | sub a, #7 373 | 00002$: 374 | add a, #'0'+1 375 | ld (1, x), a 376 | clr (2, x) 377 | __endasm; 378 | #else 379 | *hex = val >> 4; 380 | if (*hex > 9) 381 | *hex += 7; 382 | *hex += '0'; 383 | hex++; 384 | *hex = val & 0x0f; 385 | if (*hex > 9) 386 | *hex += 7; 387 | *hex += '0'; 388 | hex++; 389 | *hex = 0; 390 | #endif 391 | } 392 | 393 | /****************************************************************************** 394 | * 395 | * Convert ASCII decimal digits to 16-bit binary 396 | * Stops on first non-decimal character 397 | */ 398 | #pragma disable_warning 59 399 | 400 | int dec_bin16(char *dec) 401 | { 402 | dec; 403 | __asm 404 | #if __SDCCCALL == 0 405 | ldw y, (3, sp) 406 | #else 407 | ldw y, x 408 | #endif 409 | clrw x 410 | pushw x 411 | 00001$: 412 | ld a, (y) 413 | incw y 414 | sub a, #'0' 415 | jrc 00090$ 416 | cp a, #10 417 | jrnc 00090$ 418 | 419 | ldw x, (1, sp) 420 | sllw x 421 | sllw x 422 | addw x, (1, sp) 423 | sllw x 424 | ldw (1, sp), x 425 | 426 | add a, (2, sp) 427 | ld (2, sp), a 428 | jrnc 00001$ 429 | inc (1, sp) 430 | jra 00001$ 431 | 00090$: 432 | ldw x, (1, sp) 433 | add sp, #2 434 | __endasm; 435 | } 436 | 437 | /****************************************************************************** 438 | * 439 | * Convert ASCII decimal digits to 16-bit binary 440 | * Digits may be preceded with sign 441 | * Stops on first non-decimal character 442 | */ 443 | int dec_bin16s(char *dec) 444 | { 445 | if (*dec == '-') 446 | return -dec_bin16(dec + 1); 447 | if (*dec == '+') 448 | dec++; 449 | return dec_bin16(dec); 450 | } 451 | -------------------------------------------------------------------------------- /lib_bindec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_bindec.h 3 | * Date first: 12/24/2017 4 | * Date last: 12/18/2018 5 | * 6 | * Description: Library of binary/decimal functions for STM8 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Convert 16 bit unsigned binary to 5 digit decimal, terminate with zero 16 | */ 17 | 18 | void bin16_dec(short, char *); 19 | 20 | /* 21 | * Convert 32 bit unsigned binary to 10 digit decimal, terminate with zero 22 | */ 23 | 24 | void bin32_dec(long, char *); 25 | 26 | /* 27 | * Convert 8 bit unsigned binary to 2 digit decimal, terminate with zero 28 | */ 29 | 30 | void bin8_dec2(char, char *); 31 | 32 | /* 33 | * Trim leading zeroes from decimal buffer 34 | * in: buffer, maximum zeroes to remove 35 | * out: first non-zero digit 36 | */ 37 | 38 | char *decimal_rlz(char *, char); 39 | 40 | /* 41 | * Combine 16 bit binary to decimal and remove leading zeroes 42 | * in: 16 bit binary, 6 digit buffer 43 | * out: first non-zero digit 44 | */ 45 | 46 | char *bin16_dec_rlz(short, char *); 47 | 48 | /* 49 | * Convert binary byte to hex, terminate with zero 50 | */ 51 | 52 | void bin8_hex(char, char *); 53 | 54 | /* 55 | * Convert ASCII decimal digits to 16-bit binary 56 | * Stops on first non-decimal character 57 | */ 58 | 59 | int dec_bin16(char *); 60 | 61 | /* 62 | * Convert ASCII decimal digits to 16-bit binary 63 | * Digits may be preceded with sign 64 | * Stops on first non-decimal character 65 | */ 66 | int dec_bin16s(char *); 67 | -------------------------------------------------------------------------------- /lib_board.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_board.c 3 | * Date first: 07/01/2019 4 | * Date last: 07/01/2019 5 | * 6 | * Description: STM8 Library for popular board support (stm8s103F3, stm8s105). 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2019 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "stm8s_header.h" 18 | #include "lib_board.h" 19 | 20 | /****************************************************************************** 21 | * 22 | * Initialize board 23 | * 24 | * Board frequency override may be added later. 25 | * Default is 16mhz internal for stm8s103 and 8mhz external xtal for stm8s105. 26 | * SQU board for CAN uses the 16mhz crystal. 27 | */ 28 | 29 | void board_init(char freq) 30 | { 31 | freq; 32 | #ifdef STM8103 33 | CLK_CKDIVR = 0x00; /* clock 16mhz internal for STM8S103 */ 34 | 35 | PB_DDR = 0x20; /* output LED */ 36 | PB_CR1 = 0xff; /* inputs have pullup */ 37 | PB_CR2 = 0x00; /* no interrupts, 2mhz output */ 38 | 39 | #endif 40 | #ifdef STM8105 41 | CLK_CKDIVR = 0x00; /* no clock divisor */ 42 | CLK_ECKR = 1; /* enable crystal oscillator */ 43 | CLK_SWCR = 2; /* enable clock switch */ 44 | CLK_SWR = 0xb4; /* HSE is master (8 mhz crystal) */ 45 | 46 | PE_DDR = 0x20; /* output LED */ 47 | PE_CR1 = 0x20; 48 | #endif 49 | #ifdef STM8S207 50 | CLK_CKDIVR = 0x00; /* no clock divisor */ 51 | CLK_ECKR = 1; /* enable crystal oscillator */ 52 | CLK_SWCR = 2; /* enable clock switch */ 53 | CLK_SWR = 0xb4; /* HSE is master (16 mhz crystal) */ 54 | #endif 55 | __ASM 56 | rim 57 | __ENDASM 58 | } 59 | 60 | /* Available ports on STM8S103P3: 61 | * 62 | * A1..A3 A3 is HS 63 | * B4..B5 Open drain 64 | * C3..C7 HS 65 | * D1..D6 HS 66 | * 67 | * Available ports on 105 demo board: 68 | * 69 | * A1-A2 slow (crystal) (A3 lost from 103) 70 | * B0-B5 slow 71 | * C1-C7 fast all high sink 72 | * D0-D4 fast and high sink 73 | * D5-D7 slow (D5/D6 UART) 74 | * E5 slow LED 75 | * F4 slow 76 | * 77 | ****************************************************************************** 78 | * 79 | * Turn LED on or off. 80 | * in: zero = off, non-zero = on 81 | */ 82 | 83 | void board_led(char on) 84 | { 85 | #ifdef STM8103 86 | if (on) 87 | PB_ODR &= 0xdf; 88 | else 89 | PB_ODR |= 0x20; 90 | #endif 91 | #ifdef STM8105 92 | if (on) 93 | PE_ODR &= 0xdf; 94 | else 95 | PE_ODR |= 0x20; 96 | #endif 97 | #ifdef STM8S207 98 | if (on) 99 | PD_ODR |= 0x80; 100 | else 101 | PD_ODR &= 0x7f; 102 | 103 | #endif 104 | } 105 | 106 | -------------------------------------------------------------------------------- /lib_board.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_board.h 3 | * Date first: 07/01/2019 4 | * Date last: 07/01/2019 5 | * 6 | * Description: STM8 Library for popular board support (stm8s103, stm8s105). 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2019 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize board 16 | * 17 | * Board frequency override may be added later. 18 | * Default is 16mhz internal for stm8s103 and 8mhz external xtal for stm8s105. 19 | */ 20 | 21 | void board_init(char freq); 22 | 23 | /* 24 | * Turn LED on or off. 25 | * in: zero = off, non-zero = on 26 | */ 27 | 28 | void board_led(char on); 29 | -------------------------------------------------------------------------------- /lib_cap2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_cap2.c 3 | * Date first: 01/08/2018 4 | * Date last: 10/21/2018 5 | * 6 | * Description: STM8 Library for capture on Timer2 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Pinout: 16 | * 17 | * Pin 1, PD4: Timer2 channel 1 18 | */ 19 | 20 | #include "stm8s_header.h" 21 | #include "lib_cap2.h" 22 | 23 | /****************************************************************************** 24 | * 25 | * Capture memory 26 | */ 27 | 28 | int cap2_buf[16]; 29 | int cap2_last; 30 | int cap2_ovfl; 31 | volatile char cap2_ptr_get; 32 | volatile char cap2_ptr_put; 33 | 34 | /****************************************************************************** 35 | * 36 | * Set up timer2 for capture 37 | */ 38 | 39 | void cap2_init(char prescale) 40 | { 41 | cap2_ptr_get = 0; 42 | cap2_ptr_put = 0; 43 | cap2_ovfl = 0; 44 | cap2_last = 0; 45 | 46 | TIM2_IER = TIMx_CC1IE; /* interrupt on input 1 compare */ 47 | TIM2_EGR = TIMx_CC1G; /* capture on input 1 */ 48 | TIM2_CCMR1 = 1; /* no filter, no PS, IC1 mapped on TI1FP1 */ 49 | TIM2_CCER1 = TIMx_CC1P | TIMx_CC1E; /* capture on falling edge */ 50 | TIM2_PSCR = prescale; /* prescaler = 2^N */ 51 | 52 | TIM2_CR1 = TIMx_CEN; /* enable counter, don't reload */ 53 | } 54 | 55 | /****************************************************************************** 56 | * 57 | * Get number of captures waiting 58 | */ 59 | 60 | char cap2_count(void) 61 | { 62 | char count; 63 | 64 | count = cap2_ptr_put - cap2_ptr_get; 65 | if (count & 0x80) /* pointer wrap */ 66 | count += 16; 67 | return count; 68 | } 69 | 70 | /****************************************************************************** 71 | * 72 | * Get next capture count (wait if needed) 73 | */ 74 | 75 | int cap2_get(void) 76 | { 77 | int val; 78 | 79 | while (cap2_ptr_get == cap2_ptr_put); 80 | 81 | val = cap2_buf[cap2_ptr_get]; 82 | cap2_ptr_get++; 83 | cap2_ptr_get &= 0x0f; 84 | 85 | return val; 86 | } 87 | 88 | /****************************************************************************** 89 | * 90 | * Get overflow count 91 | */ 92 | 93 | int cap2_overflow(void) 94 | { 95 | return cap2_ovfl; 96 | } 97 | 98 | /****************************************************************************** 99 | * 100 | * Timer2 capture interrupt 101 | */ 102 | 103 | void cap2_isr(void) __interrupt (IRQ_TIM2C) 104 | { 105 | int cap_cur; 106 | char ptr_new; 107 | 108 | TIM2_CCER1 ^= TIMx_CC1P; /* change edge polarity */ 109 | 110 | cap_cur = (TIM2_CCR1H << 8) + TIM2_CCR1L; 111 | cap2_buf[cap2_ptr_put] = cap_cur - cap2_last; 112 | cap2_last = cap_cur; 113 | 114 | ptr_new = cap2_ptr_put + 1; 115 | ptr_new &= 15; 116 | if (ptr_new == cap2_ptr_get) 117 | cap2_ovfl++; 118 | else 119 | cap2_ptr_put = ptr_new; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /lib_cap2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_cap2.h 3 | * Date first: 01/08/2018 4 | * Date last: 01/09/2018 5 | * 6 | * Description: STM8 Library for capture on Timer2 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize timer2 for capture 16 | * in: timer prescaler 17 | */ 18 | 19 | void cap2_init(char); 20 | 21 | #define CAP2_16_MHZ 0 /* capture up to 4 ms */ 22 | #define CAP2_1_US 4 /* capture up to 65 ms */ 23 | #define CAP2_4_US 6 /* capture up to 1/4 sec */ 24 | #define CAP2_1_MS 14 /* capture up to 65 sec */ 25 | 26 | /* 27 | * Get count of captures waiting 28 | */ 29 | 30 | char cap2_count(void); 31 | 32 | /* 33 | * Get capture value (wait if needed) 34 | */ 35 | 36 | int cap2_get(void); 37 | 38 | /* 39 | * Get overflow count 40 | */ 41 | 42 | int cap2_overflow(void); 43 | 44 | /* 45 | * Interrupt prototypes must be included with main() 46 | */ 47 | 48 | #include "vectors.h" 49 | 50 | void cap2_isr(void) __interrupt (IRQ_TIM2C); 51 | -------------------------------------------------------------------------------- /lib_cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_cli.c 3 | * Date first: 02/19/2018 4 | * Date last: 02/23/2018 5 | * 6 | * Description: STM8 Library for handling commands from input source. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "lib_cli.h" 18 | 19 | #define CMD_CR 0x0d 20 | #define CMD_BELL 0x07 21 | #define CMD_BS 0x08 22 | #define CMD_CRLF "\r\n" 23 | 24 | static char cmpkey(char *, char *); /* compare keyword */ 25 | static char toupper(char); 26 | static char tolower(char); 27 | 28 | static COMMAND_TAB *command_tab; 29 | static char command_len; 30 | static char *buf_in; 31 | static char buf_len; 32 | 33 | static char *cmd_ptr; 34 | static char cmd_len; 35 | 36 | static char (*getc)(void); 37 | static void (*putc)(char); 38 | static char (*rxct)(void); 39 | 40 | /****************************************************************************** 41 | * 42 | * Command init 43 | * in: COMMAND_TAB, tab size, command buffer, buffer size 44 | */ 45 | 46 | void cli_init(COMMAND_CTX *ctx) 47 | { 48 | command_tab = ctx->tab; 49 | buf_in = ctx->buf_in; 50 | buf_len = ctx->buf_len - 1; 51 | 52 | getc = ctx->getc; 53 | putc = ctx->putc; 54 | rxct = ctx->size; 55 | 56 | cmd_ptr = buf_in; 57 | cmd_len = 0; 58 | *cmd_ptr = 0; 59 | } 60 | 61 | /****************************************************************************** 62 | * 63 | * Poll for command characters 64 | * out: non-zero = line ready 65 | */ 66 | 67 | char cli_poll(void) 68 | { 69 | char cmdchr; 70 | 71 | while (rxct()) { 72 | cmdchr = getc(); 73 | if (cmdchr == CMD_CR) 74 | return 1; 75 | if (cmdchr == CMD_BS) { 76 | if (!cmd_len) 77 | continue; 78 | cmd_len--; 79 | cmd_ptr--; 80 | *cmd_ptr = 0; 81 | putc(CMD_BS); 82 | putc(' '); 83 | putc(CMD_BS); 84 | continue; 85 | } 86 | if (cmd_len == buf_len) { 87 | putc(CMD_BELL); 88 | continue; 89 | } 90 | putc(cmdchr); 91 | *cmd_ptr = cmdchr; 92 | cmd_len++; 93 | cmd_ptr++; 94 | *cmd_ptr = 0; 95 | } 96 | return 0; 97 | } 98 | 99 | /****************************************************************************** 100 | * 101 | * Get keyword number 102 | * out: command number or zero (invalid) 103 | */ 104 | 105 | char cli_keynum(char *str) 106 | { 107 | COMMAND_TAB *tab; 108 | 109 | tab = command_tab; 110 | while (tab->cmd_num) { 111 | if (cmpkey(str, tab->cmd_name) == 0) 112 | return tab->cmd_num; 113 | tab++; 114 | } 115 | return 0; 116 | } 117 | 118 | /****************************************************************************** 119 | * 120 | * Show available commands 121 | */ 122 | 123 | static void puts(char *str) 124 | { 125 | while (*str) 126 | putc(*str++); 127 | } 128 | 129 | void cli_help(void) 130 | { 131 | COMMAND_TAB *tab; 132 | 133 | tab = command_tab; 134 | while (tab->cmd_num) { 135 | puts(tab->cmd_name); 136 | putc(9); 137 | puts(tab->cmd_info); 138 | putc(0x0d); 139 | putc(0x0a); 140 | 141 | tab++; 142 | } 143 | } 144 | 145 | /****************************************************************************** 146 | * 147 | * Reset command line 148 | */ 149 | 150 | void cli_reset(void) 151 | { 152 | cmd_ptr = buf_in; 153 | cmd_len = 0; 154 | *cmd_ptr = 0; 155 | } 156 | 157 | /****************************************************************************** 158 | * 159 | * Function using inline assembly follow. 160 | * Remove compiler warnings that functions "must return value" 161 | */ 162 | 163 | #pragma disable_warning 59 164 | 165 | /****************************************************************************** 166 | * 167 | * Trim whitespace from string 168 | * out: final string length 169 | */ 170 | 171 | char cli_trim (char *s) 172 | { 173 | s; 174 | __asm 175 | ldw x, (3, sp) 176 | ldw y, (3, sp) 177 | push #0 ; not in quotes 178 | push #0 ; final length 179 | push #' ' ; pretend previous space 180 | 181 | 00001$: 182 | ld a, (x) 183 | jreq 00090$ 184 | incw x 185 | tnz (3, sp) ; inside quotes? 186 | jrne 00009$ ; do not trim inside quote 187 | cp a, #' ' 188 | jrne 00009$ 189 | tnz (1, sp) 190 | jrne 00001$ 191 | ld (1, sp),a 192 | ld (y), a 193 | incw y 194 | inc (2, sp) 195 | jra 00001$ 196 | 197 | 00009$: 198 | ld (y), a 199 | incw y 200 | inc (2, sp) 201 | clr (1, sp) 202 | cp a, #'"' 203 | jrne 00001$ 204 | cpl (3, sp) 205 | jra 00001$ 206 | 207 | 00090$: 208 | tnz (1, sp) ; trailing space? 209 | jreq 00091$ 210 | tnz (2, sp) ; only spaces? 211 | jreq 00091$ 212 | decw y 213 | 00091$: 214 | clr (y) 215 | ld a, (2, sp) 216 | addw sp, #3 217 | __endasm; 218 | } 219 | 220 | /****************************************************************************** 221 | * 222 | * Tokenize command line 223 | * in: command line, token pointer list, max tokens 224 | * out: token count 225 | */ 226 | 227 | char cli_tokenize(char *inbuf, char **toklist, char tokmax) 228 | { 229 | inbuf, toklist, tokmax; 230 | __asm 231 | ldw x, (3, sp) 232 | ldw y, (5, sp) 233 | ld a, (7, sp) 234 | 235 | push #0 ; (2, sp) token count 236 | push #0 ; (1, sp) quote flag 237 | 238 | 00001$: 239 | ld a, (x) 240 | jreq 00090$ 241 | cp a, #'"' ; does token start with quote? 242 | jrne 00003$ 243 | incw x 244 | cpl (1, sp) 245 | 00003$: 246 | ldw (y), x 247 | incw y 248 | incw y 249 | inc (2, sp) 250 | dec (9, sp) 251 | jreq 00090$ 252 | 253 | 00005$: 254 | ld a, (x) 255 | jreq 00090$ 256 | incw x 257 | cp a, #'"' 258 | jreq 00010$ 259 | tnz (1, sp) ; inside quote? 260 | jrne 00005$ ; leave quoted token alone 261 | 262 | cp a, #' ' ; space ends token 263 | jrne 00005$ 264 | decw x 265 | clr (x) ; terminate token 266 | incw x 267 | jra 00001$ 268 | 269 | 00010$: 270 | decw x 271 | clr (x) ; quote is now end of token 272 | incw x 273 | cpl (1, sp) 274 | jrne 00001$ ; starting new token inside quote 275 | ld a, (x) 276 | cp a, #' ' ; end quote followed by space? 277 | jrne 00001$ 278 | incw x ; skip space 279 | jra 00001$ 280 | 281 | 00090$: 282 | ld a, (2, sp) 283 | addw sp, #2 284 | __endasm; 285 | } 286 | 287 | /****************************************************************************** 288 | * 289 | * Remove comment from string (comment char inside double quotes ignored) 290 | * in: string, 4 character string with comment chars (eg, "#;;;") 291 | */ 292 | 293 | void cli_comment(char *buf, char *comment) 294 | { 295 | buf, comment; 296 | __asm 297 | ldw y, (3, sp) 298 | ldw x, (5, sp) 299 | push #0 ; quotes flag 300 | 00001$: 301 | ld a, (y) 302 | jreq 00095$ 303 | incw y 304 | cp a, #'"' 305 | jreq 00010$ 306 | tnz (1, sp) ; inside quotes? 307 | jrne 00001$ 308 | cp a, (x) 309 | jreq 00005$ 310 | cp a, (1, x) 311 | jreq 00005$ 312 | cp a, (2, x) 313 | jreq 00005$ 314 | cp a, (3, x) 315 | jrne 00001$ 316 | 00005$: 317 | decw y 318 | clr (y) 319 | jra 00095$ 320 | 00010$: 321 | cpl (1, sp) 322 | jra 00001$ 323 | 00095$: 324 | addw sp, #1 325 | __endasm; 326 | } 327 | 328 | /****************************************************************************** 329 | * 330 | * Make uppercase 331 | */ 332 | 333 | static char toupper(char c) 334 | { 335 | c; 336 | __asm 337 | cp a, #'a' 338 | jrc 00001$ 339 | cp a, #'z' + 1 340 | jrnc 00001$ 341 | sub a, #0x20 342 | 00001$: 343 | __endasm; 344 | } 345 | 346 | static char tolower(char c) 347 | { 348 | c; 349 | __asm 350 | cp a, #'A' 351 | jrc 00001$ 352 | cp a, #'Z' + 1 353 | jrnc 00001$ 354 | add a, #0x20 355 | 00001$: 356 | __endasm; 357 | } 358 | 359 | /****************************************************************************** 360 | * 361 | * Compare keywords 362 | * 363 | * in: word 1 (upper/lower), word 2 (lowercase) 364 | * out: zero = match 365 | */ 366 | 367 | static char cmpkey(char *in, char *list) 368 | { 369 | in, list; 370 | __asm 371 | ldw x, (3, sp) 372 | ldw y, (5, sp) 373 | 00001$: 374 | ld a, (y) 375 | jreq 00090$ 376 | incw y 377 | call _tolower 378 | sub a, (x) 379 | jrne 00090$ 380 | incw x 381 | jra 00001$ 382 | 00090$: 383 | __endasm; 384 | } 385 | -------------------------------------------------------------------------------- /lib_cli.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_cli.h 3 | * Date first: 02/19/2018 4 | * Date last: 03/23/2018 5 | * 6 | * Description: STM8 Library for handling commands from input source. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Command structure 16 | */ 17 | 18 | typedef struct { 19 | char cmd_num; /* up to 255 commands */ 20 | char *cmd_name; /* case insensitive */ 21 | char *cmd_info; /* command help or NULL */ 22 | } COMMAND_TAB; 23 | 24 | typedef struct { 25 | COMMAND_TAB *tab; /* command table */ 26 | char *buf_in; /* input buffer */ 27 | char buf_len; 28 | char (*getc)(void); /* char get function */ 29 | void (*putc)(char); /* char put function */ 30 | char (*size)(void); /* rx buf count */ 31 | } COMMAND_CTX; 32 | 33 | /* 34 | * Command init 35 | * in: COMMAND_TAB, tab size, command buffer, buffer size 36 | */ 37 | 38 | void cli_init(COMMAND_CTX *); 39 | 40 | /* 41 | * Poll UART for command characters 42 | * out: non-zero = line ready 43 | */ 44 | 45 | char cli_poll(void); 46 | 47 | /* 48 | * Get command number 49 | * out: command number or zero (invalid) 50 | */ 51 | 52 | char cli_keynum(char *); 53 | 54 | /* 55 | * Reset command line 56 | */ 57 | 58 | void cli_reset(void); 59 | 60 | /* 61 | * Remove comment from string (comment char inside double quotes ignored) 62 | * in: string, 4 character string with comment chars (eg, "#;;;") 63 | */ 64 | 65 | void cli_comment(char *, char *); 66 | 67 | /* 68 | * Trim whitespace from buffer 69 | * Spaces inside double quotes are left intact. 70 | * 71 | * out: final string length 72 | */ 73 | 74 | char cli_trim(char *); 75 | 76 | /* 77 | * Tokenize string 78 | * 79 | * Extra whitespace must be trimmed first. Suggest cli_trim() above. 80 | * Tokens are separated by spaces or double quotes. 81 | * Any string inside double quotes is a single token and the quotes are removed. 82 | * An empty string returns a token count of zero. 83 | * Any excess tokens above max # are not processed and show in the last token. 84 | * 85 | * in: string, token pointers, max token count 86 | * out: token count 87 | */ 88 | 89 | char cli_tokenize(char *, char **, char); 90 | 91 | /* 92 | * Print available commands 93 | */ 94 | 95 | void cli_help(void); 96 | -------------------------------------------------------------------------------- /lib_clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_clock.c 3 | * Date first: 03/23/2018 4 | * Date last: 04/18/2018 5 | * 6 | * Description: Library for maintaining a wall clock using timer 4 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "stm8s_header.h" 18 | 19 | #include "lib_bindec.h" 20 | #include "lib_clock.h" 21 | 22 | static signed char clock_ms; /* milliseconds, may be negative with trim */ 23 | static char clock_tenths; /* clock tenths: 0-9 */ 24 | static char clock_secs; /* clock seconds: 0-59 */ 25 | static char clock_mins; /* clock minutes: 0-59 */ 26 | static char clock_hours; /* clock hours: 0-23 */ 27 | static char clock_days; /* clock days: 0-255 */ 28 | 29 | static signed char trim_second; /* small trim every second */ 30 | 31 | static volatile char clock_lock; /* lock to update clock */ 32 | 33 | #ifdef CLOCK_CALENDAR 34 | static CLOCK_CAL calendar; 35 | #endif 36 | 37 | static void (*timer_ms)(void); 38 | static void (*timer_10)(void); 39 | 40 | /****************************************************************************** 41 | * 42 | * Initialize the clock (set up timer 4) 43 | * in: Millisecond callback, 1/10 second callback 44 | */ 45 | 46 | void clock_init(void (*call_ms)(void), void (*call_10)(void)) 47 | { 48 | timer_ms = call_ms; 49 | timer_10 = call_10; 50 | 51 | clock_ms = 0; 52 | clock_tenths = 0; 53 | clock_secs = 0; 54 | clock_mins = 0; 55 | clock_hours = 0; 56 | clock_days = 0; 57 | clock_lock = 0; 58 | 59 | trim_second = 0; /* millisecond trim every second */ 60 | 61 | #ifdef STM8103 62 | TIM4_PSCR = 6; /* prescaler = 64 for 16mhz */ 63 | #endif 64 | #ifdef STM8105 65 | TIM4_PSCR = 5; /* prescaler = 32 for 8mhz */ 66 | #endif 67 | TIM4_ARR = 249; /* reset and interrupt every 1.0 ms */ 68 | TIM4_CR1 = 1; /* enable timer4 */ 69 | TIM4_IER = 1; /* enable timer4 interrupt */ 70 | } 71 | 72 | /****************************************************************************** 73 | * 74 | * Get string for current clock 75 | * Formats like "22:00:00" (8 chars + zero) 76 | */ 77 | 78 | void clock_string(char *buf) 79 | { 80 | clock_lock = 1; 81 | bin8_dec2(clock_hours, buf); 82 | bin8_dec2(clock_mins, buf + 3); 83 | bin8_dec2(clock_secs, buf + 6); 84 | clock_lock = 0; 85 | buf[2] = ':'; 86 | buf[5] = ':'; 87 | } 88 | 89 | /****************************************************************************** 90 | * 91 | * Get binary values for day, hour, minute, second 92 | * out: (4 bytes set) 93 | */ 94 | 95 | void clock_bin_get(char *vals) 96 | { 97 | clock_lock = 1; 98 | vals[0] = clock_days; 99 | vals[1] = clock_hours; 100 | vals[2] = clock_mins; 101 | vals[3] = clock_secs; 102 | clock_lock = 0; 103 | } 104 | 105 | /****************************************************************************** 106 | * 107 | * Set clock from binary values 108 | * out: (4 bytes set) 109 | */ 110 | 111 | void clock_bin_set(char *vals) 112 | { 113 | clock_lock = 1; 114 | clock_days = vals[0]; 115 | clock_hours = vals[1]; 116 | clock_mins = vals[2]; 117 | clock_secs = vals[3]; 118 | clock_lock = 0; 119 | } 120 | 121 | /****************************************************************************** 122 | * 123 | * Set clock from ASCII string (Format: "22:00:00") 124 | * out: zero = success 125 | */ 126 | 127 | char clock_set(char *time) 128 | { 129 | char *t; 130 | char ct, h, m, s; 131 | 132 | t = time; 133 | ct = 0; 134 | while (*t) 135 | if (*t++ == ':') 136 | ct++; 137 | if (ct != 2) 138 | return 1; 139 | 140 | h = dec_bin16(time); 141 | while (*time++ != ':'); 142 | m = dec_bin16(time); 143 | while (*time++ != ':'); 144 | s = dec_bin16(time); 145 | 146 | if ((h > 23) || 147 | (m > 59) || 148 | (s > 59)) 149 | return 1; 150 | 151 | clock_lock = 1; 152 | clock_hours = h; 153 | clock_mins = m; 154 | clock_secs = s; 155 | clock_lock = 0; 156 | return 0; 157 | } 158 | 159 | /****************************************************************************** 160 | * 161 | * Set large and fine clock trim 162 | * in: large +/- (0.4%), fine +/- (0.1%) 163 | */ 164 | 165 | void clock_trim(signed char large, signed char fine) 166 | { 167 | TIM4_ARR = 249 - large; 168 | trim_second = fine; 169 | } 170 | 171 | /****************************************************************************** 172 | * 173 | * Timer 4 interrupt 174 | */ 175 | 176 | void timer4_isr(void) __interrupt (IRQ_TIM4) 177 | { 178 | TIM4_SR = 0; /* clear the interrupt */ 179 | 180 | timer_ms(); 181 | clock_ms++; 182 | if (clock_lock) 183 | return; 184 | if (clock_ms < 100) 185 | return; 186 | clock_ms -= 100; 187 | 188 | timer_10(); 189 | clock_tenths++; 190 | if (clock_tenths < 10) 191 | return; 192 | clock_tenths = 0; 193 | 194 | clock_ms += trim_second; 195 | clock_secs++; 196 | if (clock_secs < 60) 197 | return; 198 | clock_secs = 0; 199 | clock_mins++; 200 | if (clock_mins < 60) 201 | return; 202 | clock_mins = 0; 203 | clock_hours++; 204 | if (clock_hours < 24) 205 | return; 206 | clock_hours = 0; 207 | clock_days++; 208 | 209 | #ifdef CLOCK_CALENDAR 210 | clock_inc_calendar(); 211 | #endif 212 | } 213 | 214 | #ifdef CLOCK_CALENDAR 215 | 216 | static const char days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 217 | 218 | /****************************************************************************** 219 | * 220 | * Advance calendar one day 221 | */ 222 | 223 | void clock_inc_calendar(void) 224 | { 225 | char mdays; 226 | 227 | calendar.day++; 228 | if (calendar.day > 7) 229 | calendar.day = 1; 230 | 231 | mdays = days[calendar.month - 1]; 232 | if (calendar.month == 2 && 233 | (calendar.year & 3) == 0) 234 | mdays++; 235 | calendar.date++; 236 | if (calendar.date <= mdays) 237 | return; 238 | calendar.date = 1; 239 | 240 | calendar.month++; 241 | if (calendar.month < 13) 242 | return; 243 | calendar.month = 1; 244 | 245 | calendar.year++; 246 | } 247 | 248 | /* NOTE: This function will normally be called from the timer interrupt, and 249 | * will be protected by "clock_lock". During testing, this may also be called 250 | * from user space and that code will need to avoid possible race condition. 251 | * 252 | ****************************************************************************** 253 | * 254 | * Get calendar data 255 | * in: calendar structure 256 | */ 257 | 258 | void clock_cal_get(CLOCK_CAL *cal) 259 | { 260 | clock_lock = 1; 261 | cal->year = calendar.year; 262 | cal->month = calendar.month; 263 | cal->date = calendar.date; 264 | cal->day = calendar.day; 265 | clock_lock = 0; 266 | } 267 | 268 | /****************************************************************************** 269 | * 270 | * Set calendar data 271 | * in: calendar structure 272 | */ 273 | 274 | void clock_cal_set(CLOCK_CAL *cal) 275 | { 276 | clock_lock = 1; 277 | calendar.year = cal->year; 278 | calendar.month = cal->month; 279 | calendar.date = cal->date; 280 | calendar.day = cal->day; 281 | clock_lock = 0; 282 | } 283 | 284 | #endif /* CLOCK_CALENDAR */ 285 | -------------------------------------------------------------------------------- /lib_clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_clock.h 3 | * Date first: 03/23/2018 4 | * Date last: 08/16/2020 5 | * 6 | * Description: Library for maintaining a wall clock using timer 4 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018-2020 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Option to extend clock to handle calendar date 16 | * Comment out to save code and memory. 17 | */ 18 | 19 | #define CLOCK_CALENDAR 20 | 21 | /* 22 | * Initialize the clock (set up timer 4) 23 | * in: Millisecond callback 24 | */ 25 | 26 | void clock_init(void (*)(void), void (*)(void)); 27 | 28 | /* 29 | * Get string for current clock 30 | * Formats like "22:00:00" (8 chars + zero) 31 | */ 32 | 33 | void clock_string(char *); 34 | 35 | /* 36 | * Set clock from ASCII string 37 | * Format: "22:00:00" 38 | */ 39 | 40 | char clock_set(char *); 41 | 42 | /* 43 | * Get/set binary values for day, hour, minute, second 44 | * out: (4 bytes set) 45 | */ 46 | 47 | void clock_bin_get(char *); 48 | void clock_bin_set(char *); 49 | 50 | /* 51 | * Set large and fine clock trim 52 | * Positive values speed up, negative values slow down 53 | * in: large +/- (0.4%), fine +/- (0.1%) 54 | */ 55 | 56 | void clock_trim(signed char, signed char); 57 | 58 | void timer4_isr(void) __interrupt (IRQ_TIM4); 59 | 60 | /* 61 | * OPTIONAL CALENDAR FUNCTIONS 62 | */ 63 | #ifdef CLOCK_CALENDAR 64 | typedef struct { 65 | int year; /* 2000-2199 */ 66 | char month; /* 1-12 */ 67 | char date; /* 1-31 */ 68 | char day; /* 1-7 */ 69 | } CLOCK_CAL; 70 | 71 | /* 72 | * Get or set current year, month, date, day of week 73 | */ 74 | void clock_cal_get(CLOCK_CAL *); 75 | void clock_cal_set(CLOCK_CAL *); 76 | 77 | /* 78 | * Advance the calendar date (for testing calendar function) 79 | */ 80 | void clock_inc_calendar(void); 81 | 82 | #endif /* CLOCK_CALENDAR */ 83 | -------------------------------------------------------------------------------- /lib_delay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_delay.h 3 | * Date first: 12/19/2017 4 | * Date last: 09/16/2022 5 | * 6 | * Description: STM8 Library for short delays. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018, 2022 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * Code copied out of lib_lcd.c 14 | * 15 | ****************************************************************************** 16 | * 17 | * Delays assume 16mhz on stms103 and 8 mhz on stm8s105 18 | */ 19 | #include "lib_delay.h" 20 | 21 | void delay_500ns(void) 22 | { 23 | /* call (4) + return (4) == 500 uS */ 24 | } 25 | void delay_50us(void) 26 | { 27 | delay_usecs(50); 28 | } 29 | void delay_usecs(char usecs) 30 | { 31 | usecs; 32 | __asm 33 | #if __SDCCCALL == 0 34 | ld a, (3, sp) 35 | #endif 36 | dec a 37 | clrw x 38 | ld xl,a 39 | #ifdef STM8103 40 | sllw x 41 | #endif 42 | sllw x 43 | 00001$: 44 | nop ; (1) 45 | decw x ; (1) 46 | jrne 00001$ ; (2) 47 | __endasm; 48 | } 49 | 50 | void delay_ms(unsigned char wait) 51 | { 52 | while (wait--) { 53 | delay_usecs(250); 54 | delay_usecs(250); 55 | delay_usecs(250); 56 | delay_usecs(250); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib_delay.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_delay.h 3 | * Date first: 11/05/2018 4 | * Date last: 11/05/2018 5 | * 6 | * Description: STM8 Library for short delays. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Delays 16 | */ 17 | void delay_500ns(void); /* 500 microseconds */ 18 | void delay_usecs(char); /* 1 to 255 microseconds */ 19 | void delay_50us(void); /* 50 microseconds */ 20 | void delay_ms(unsigned char); /* 1 to 255 milliseconds (setup code) */ 21 | -------------------------------------------------------------------------------- /lib_eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_eeprom.c 3 | * Date first: code clipped from lib_log 4 | * Date last: 08/21/2018 5 | * 6 | * Description: Library for EEPROM functions 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | */ 15 | 16 | #include "stm8s_header.h" 17 | 18 | #include "lib_eeprom.h" 19 | 20 | /****************************************************************************** 21 | * 22 | * Unlock EEPROM for writing 23 | * out: zero = fail 24 | */ 25 | #pragma disable_warning 59 26 | 27 | char eeprom_unlock(void) 28 | { 29 | __asm 30 | mov _FLASH_DUKR, #0xae 31 | mov _FLASH_DUKR, #0x56 32 | clr a 33 | 00001$: 34 | dec a 35 | jreq 00090$ 36 | btjf _FLASH_IAPSR, #3, 00001$ 37 | 00090$: 38 | __endasm; 39 | } 40 | 41 | /****************************************************************************** 42 | * 43 | * Lock EEPROM from writing after write 44 | */ 45 | 46 | void eeprom_lock(void) 47 | { 48 | __asm 49 | bres _FLASH_IAPSR, #3 50 | __endasm; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /lib_eeprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_eeprom.h 3 | * Date first: code clipped from lib_log 4 | * Date last: 08/21/2018 5 | * 6 | * Description: Library for EEPROM functions 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Unlock the EEPROM for writing 16 | * out: zero = fail 17 | */ 18 | 19 | char eeprom_unlock(void); 20 | 21 | /* 22 | * Lock EEPROM after writing 23 | */ 24 | 25 | void eeprom_lock(void); 26 | 27 | /* 28 | * Write word to EEPROM 29 | * in: source, dest 30 | */ 31 | -------------------------------------------------------------------------------- /lib_flash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_flash.c 3 | * Date first: code clipped from lib_log 4 | * Date last: 10/18/2018 5 | * 6 | * Description: Library for Flash memory functions 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | */ 15 | 16 | #include 17 | 18 | #include "stm8s_header.h" 19 | 20 | #include "lib_flash.h" 21 | 22 | #ifdef FLASH_BLOCK_ERASE 23 | static char p_flash_erase(char *); 24 | static char r_flash_erase[30]; 25 | #endif 26 | 27 | #pragma disable_warning 59 28 | 29 | /****************************************************************************** 30 | * 31 | * Initialize Flash functions 32 | * (Need to execute block erase from RAM) 33 | */ 34 | 35 | void flash_init(void) 36 | { 37 | #ifdef FLASH_BLOCK_ERASE 38 | memcpy(r_flash_erase, p_flash_erase, 30); 39 | #endif 40 | } 41 | 42 | #ifdef FLASH_BLOCK_ERASE 43 | /****************************************************************************** 44 | * 45 | * Erase FLASH block (64 or 128 bytes) 46 | * in: block address 47 | * out: zero = success 48 | */ 49 | 50 | char flash_erase(char *ptr) 51 | { 52 | ptr; 53 | __asm 54 | ldw x, (3, sp) 55 | clr a 56 | push cc 57 | sim 58 | call _r_flash_erase 59 | pop cc 60 | __endasm; 61 | } 62 | 63 | static char p_flash_erase(char *ptr) 64 | { 65 | ptr; 66 | __asm 67 | bset _FLASH_CR2, #5 68 | bres _FLASH_NCR2, #5 69 | ld (x), a 70 | ld (1, x), a 71 | ld (2, x), a 72 | ld (3, x), a 73 | ldw x, #4000*16/5 74 | 00001$: 75 | decw x 76 | jreq 00090$ 77 | btjt _FLASH_CR2, #5, 00001$ 78 | ret 79 | 00090$: 80 | inc a 81 | __endasm; 82 | } 83 | #endif /* FLASH_BLOCK_ERASE */ 84 | 85 | /****************************************************************************** 86 | * 87 | * Unlock FLASH for writing 88 | * out: zero = fail 89 | */ 90 | 91 | char flash_unlock(void) 92 | { 93 | __asm 94 | mov _FLASH_PUKR, #0x56 95 | mov _FLASH_PUKR, #0xae 96 | clr a 97 | 00001$: 98 | dec a 99 | jreq 00090$ 100 | btjf _FLASH_IAPSR, #1, 00001$ 101 | 00090$: 102 | __endasm; 103 | } 104 | 105 | /****************************************************************************** 106 | * 107 | * Lock FLASH from writing after write 108 | */ 109 | 110 | void flash_lock(void) 111 | { 112 | __asm 113 | bres _FLASH_IAPSR, #1 114 | __endasm; 115 | } 116 | 117 | /****************************************************************************** 118 | * 119 | * Clear range of Flash memory 120 | * in: block base, size in bytes 121 | * out: zero = success 122 | */ 123 | char flash_clear(char *ptr, int size) 124 | { 125 | char retval; 126 | 127 | retval = flash_unlock(); 128 | if (!retval) 129 | return 1; 130 | #ifdef FLASH_BLOCK_ERASE 131 | while (((int)ptr & (FLASH_BLOCK - 1)) && size) { 132 | *ptr = 0; 133 | ptr++; 134 | size--; 135 | } 136 | while (size >= FLASH_BLOCK) { 137 | retval |= flash_erase(ptr); 138 | ptr += FLASH_BLOCK; 139 | size -= FLASH_BLOCK; 140 | } 141 | #endif 142 | while (size) { 143 | *ptr = 0; 144 | ptr++; 145 | size--; 146 | } 147 | flash_lock(); 148 | return retval; 149 | } 150 | -------------------------------------------------------------------------------- /lib_flash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_flash.h 3 | * Date first: code clipped from lib_log 4 | * Date last: 10/18/2018 5 | * 6 | * Description: Library for Flash memory functions 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize Flash functions 16 | */ 17 | void flash_init(void); 18 | 19 | /* 20 | * Unlock the Flash for writing 21 | * out: zero = fail 22 | */ 23 | 24 | char flash_unlock(void); 25 | 26 | /* 27 | * Lock Flash after writing 28 | */ 29 | 30 | void flash_lock(void); 31 | 32 | #define FLASH_BLOCK_ERASE /* comment out to save setup and 30 bytes of RAM */ 33 | 34 | /* 35 | * Erase FLASH block (64 or 128 bytes) 36 | * in: block address 37 | * out: zero = success 38 | */ 39 | 40 | char flash_erase(char *); 41 | 42 | /* 43 | * Clear range of Flash memory 44 | * in: block base, size in bytes 45 | * out: zero = success 46 | */ 47 | char flash_clear(char *, int); 48 | -------------------------------------------------------------------------------- /lib_i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_i2c.c 3 | * Date first: 05/17/2018 4 | * Date last: 01/29/2019 5 | * 6 | * Description: Library for communicating with I2C devices. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018, 2019 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | #include "stm8s_header.h" 17 | #include "lib_i2c.h" 18 | 19 | /* 20 | * I2C pins, PD2=clock, PD3=data 21 | * (On STM8S103 board, D3 is next to 5v, for easy pull-up resistor) 22 | */ 23 | 24 | #define I2C_CLOCK_DDR _PD_DDR 25 | #define I2C_CLOCK_ODR _PD_ODR 26 | #define I2C_CLOCK_CR1 _PD_CR1 27 | #define I2C_CLOCK_CR2 _PD_CR2 28 | #define I2C_CLOCK_PIN 2 29 | 30 | #define I2C_DATA_DDR _PD_DDR 31 | #define I2C_DATA_ODR _PD_ODR 32 | #define I2C_DATA_IDR _PD_IDR 33 | #define I2C_DATA_CR1 _PD_CR1 34 | #define I2C_DATA_CR2 _PD_CR2 35 | #define I2C_DATA_PIN 3 36 | 37 | static void i2c_rxbit(void); 38 | 39 | #warning "I2C clock and data have been moved from D1 and D2 to D2 and D3." 40 | #warning "Please change code or connections and remove this warning." 41 | 42 | /****************************************************************************** 43 | * 44 | * Initialize 45 | */ 46 | 47 | void i2c_init(void) 48 | { 49 | __asm 50 | bset I2C_CLOCK_DDR, # I2C_CLOCK_PIN 51 | bset I2C_CLOCK_CR1, # I2C_CLOCK_PIN ; no open drain 52 | 53 | bres I2C_DATA_DDR, # I2C_DATA_PIN 54 | bres I2C_DATA_ODR, # I2C_DATA_PIN ; zero when output 55 | bset I2C_DATA_CR1, # I2C_DATA_PIN ; pullup when input 56 | __endasm; 57 | 58 | i2c_clock0(); /* prevent start or stop codes */ 59 | i2c_data1(); /* safely raise data */ 60 | i2c_clock1(); /* now clock=data=1 */ 61 | 62 | 63 | } 64 | 65 | /****************************************************************************** 66 | * 67 | * Transmit 8 bits 68 | */ 69 | 70 | void i2c_txbit8(char bits) 71 | { 72 | bits; 73 | __asm 74 | push #8 75 | 00001$: 76 | #if __SDCCCALL == 0 77 | sll (4, sp) 78 | #else 79 | sll a 80 | #endif 81 | jrnc 00010$ 82 | call _i2c_data1 83 | call _i2c_data1 84 | call _i2c_data1 85 | jra 00020$ 86 | 00010$: 87 | call _i2c_data0 88 | 00020$: 89 | call _i2c_clock1 90 | call _i2c_clock1 91 | call _i2c_clock0 92 | 93 | dec (1, sp) 94 | jrne 00001$ 95 | 96 | add sp, #1 97 | __endasm; 98 | } 99 | 100 | /****************************************************************************** 101 | * 102 | * Receive 8 bits 103 | */ 104 | #pragma disable_warning 59 105 | 106 | char i2c_rxbit8(void) 107 | { 108 | __asm 109 | push #8 110 | 00001$: 111 | call _i2c_rxbit 112 | rlc a 113 | dec (1, sp) 114 | jrne 00001$ 115 | 116 | add sp, #1 117 | __endasm; 118 | } 119 | 120 | /****************************************************************************** 121 | * 122 | * Receive 1 bit 123 | * out: bit returned in carry flag 124 | */ 125 | 126 | static void i2c_rxbit(void) 127 | { 128 | __asm 129 | call _i2c_clock1 130 | btjt I2C_DATA_IDR, #I2C_DATA_PIN, 00001$ 131 | 00001$: 132 | call _i2c_clock0 133 | __endasm; 134 | } 135 | 136 | /****************************************************************************** 137 | * 138 | * Get ACK from slave 139 | * out: zero = timeout 140 | */ 141 | 142 | char i2c_getack(void) 143 | { 144 | __asm 145 | call _i2c_data1 146 | call _i2c_clock1 147 | clr a 148 | 00001$: 149 | dec a 150 | jreq 00090$ 151 | btjt I2C_DATA_IDR, #I2C_DATA_PIN, 00001$ 152 | 000090$: 153 | call _i2c_clock0 154 | __endasm; 155 | } 156 | 157 | /****************************************************************************** 158 | * 159 | * Send ACK or NAK to slave 160 | */ 161 | 162 | void i2c_sendack(void) 163 | { 164 | i2c_data0(); /* ACK */ 165 | i2c_clock1(); 166 | i2c_clock0(); 167 | i2c_data1(); 168 | } 169 | void i2c_sendnak(void) 170 | { 171 | i2c_data1(); /* NAK */ 172 | i2c_clock1(); 173 | i2c_clock0(); 174 | i2c_data1(); 175 | } 176 | 177 | /****************************************************************************** 178 | * 179 | * I2C Start and Stop 180 | * Start: CLK=DAT=1 -> CLK=DAT=0 181 | * Stop: CLK=0 -> CLK=DAT=1 182 | */ 183 | 184 | void i2c_start(void) 185 | { 186 | i2c_data0(); 187 | i2c_data0(); 188 | i2c_clock0(); 189 | } 190 | 191 | void i2c_stop(void) 192 | { 193 | i2c_data0(); 194 | i2c_clock1(); 195 | i2c_clock1(); 196 | i2c_data1(); 197 | } 198 | 199 | /****************************************************************************** 200 | * 201 | * Clock and data pins 202 | * call + bit + return = 9 cycles 203 | * no regs or flags modified 204 | */ 205 | 206 | void i2c_clock0(void) 207 | { 208 | __asm 209 | bres I2C_CLOCK_ODR, #I2C_CLOCK_PIN 210 | __endasm; 211 | } 212 | 213 | void i2c_clock1(void) 214 | { 215 | __asm 216 | bset I2C_CLOCK_ODR, #I2C_CLOCK_PIN 217 | __endasm; 218 | } 219 | 220 | void i2c_data0(void) 221 | { 222 | __asm 223 | bset I2C_DATA_DDR, #I2C_DATA_PIN 224 | __endasm; 225 | } 226 | 227 | void i2c_data1(void) 228 | { 229 | __asm 230 | bres I2C_DATA_DDR, #I2C_DATA_PIN 231 | __endasm; 232 | } 233 | 234 | -------------------------------------------------------------------------------- /lib_i2c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_i2c.h 3 | * Date first: 05/17/2018 4 | * Date last: 05/23/2018 5 | * 6 | * Description: Library for communicating with I2C devices. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | #include "stm8s_header.h" 17 | 18 | void i2c_init(void); 19 | 20 | void i2c_start(void); 21 | void i2c_stop(void); 22 | 23 | char i2c_rxbit8(void); 24 | void i2c_txbit8(char); 25 | char i2c_getack(void); 26 | void i2c_sendack(void); 27 | void i2c_sendnak(void); 28 | 29 | void i2c_clock0(void); 30 | void i2c_clock1(void); 31 | void i2c_data0(void); 32 | void i2c_data1(void); 33 | -------------------------------------------------------------------------------- /lib_keypad.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_keypad.c 3 | * Date first: 10/11/2018 4 | * Date last: 10/14/2018 5 | * 6 | * Description: STM8 Library for simple keypad 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "stm8s_header.h" 18 | 19 | #include "lib_keypad.h" 20 | 21 | static char *kmap, *kcur; 22 | 23 | static KP_PIN *cfg_row, *cfg_col; 24 | 25 | static char kbuf[KP_BUFSIZE]; 26 | static char kget; 27 | static char kput; 28 | 29 | static char curkey; /* current pressed key (or zero) */ 30 | static char bounce; /* debounce counter */ 31 | static char poll_count; 32 | 33 | static void add_key(char); /* add key to buffer */ 34 | static char check_key(void); /* check keypad for keypress */ 35 | static char check_row(void); /* check rows for keypress */ 36 | static void reset_cols(void); /* reset column pins */ 37 | static void reset_rows(void); 38 | 39 | #pragma disable_warning 59 40 | 41 | /****************************************************************************** 42 | * 43 | * Initialize 44 | * in: pin setup info (rows, then columns) 45 | */ 46 | 47 | void keypad_init(KP_PIN *rows, KP_PIN *cols) 48 | { 49 | cfg_row = rows; 50 | cfg_col = cols; 51 | 52 | kget = 0; 53 | kput = 0; 54 | 55 | curkey = 0; 56 | bounce = 0; 57 | poll_count = KP_POLL_MS; 58 | 59 | reset_cols(); 60 | reset_rows(); 61 | } 62 | 63 | /****************************************************************************** 64 | * 65 | * Poll for keypad status 66 | */ 67 | 68 | void keypad_poll(void) 69 | { 70 | char key; 71 | 72 | poll_count--; 73 | if (poll_count) 74 | return; 75 | poll_count = KP_POLL_MS; 76 | 77 | key = check_key(); 78 | if (!key) { 79 | if (!bounce) 80 | return; 81 | bounce--; 82 | if (bounce) 83 | return; 84 | #ifdef KP_KEY_REL 85 | add_key(curkey | 0x80); /* notify that key is released */ 86 | #endif 87 | curkey = 0; 88 | return; 89 | } 90 | reset_cols(); 91 | bounce = (KP_DEBOUNCE / KP_POLL_MS); 92 | if (curkey == key) /* key still pressed */ 93 | return; 94 | curkey = key; 95 | add_key(key); 96 | } 97 | 98 | /****************************************************************************** 99 | * 100 | * Add key to buffer 101 | * in: key 102 | */ 103 | 104 | static void add_key(char key) 105 | { 106 | kbuf[kput] = key; 107 | kput++; 108 | if (kput == KP_BUFSIZE) 109 | kput = 0; 110 | } 111 | 112 | /****************************************************************************** 113 | * 114 | * Get key from keypad 115 | * out: key or zero 116 | */ 117 | 118 | char keypad_getc(void) 119 | { 120 | char key; 121 | 122 | if (kget == kput) 123 | return 0; 124 | key = kbuf[kget]; 125 | kget++; 126 | if (kget == KP_BUFSIZE) 127 | kget = 0; 128 | return key; 129 | } 130 | 131 | /****************************************************************************** 132 | * 133 | * Install or change keypad map 134 | * in: new keypad map 135 | */ 136 | 137 | void keypad_kmap(char *map) 138 | { 139 | kmap = map; 140 | } 141 | 142 | /****************************************************************************** 143 | * 144 | * Reset column pins 145 | * Set column pins to output and set to 1 146 | */ 147 | 148 | static void reset_cols(void) 149 | { 150 | __asm 151 | ldw y, _cfg_col 152 | 00001$: 153 | ld a, (2, y) ; pin mask 154 | jreq 00090$ 155 | push a 156 | ldw x, y 157 | addw y, #3 158 | ldw x, (x) ; base of port registers 159 | or a, (x) 160 | ld (x), a ; ODR set bit 161 | ld a, (1, sp) 162 | or a, (2, x) ; DDR output 163 | ld (2, x), a 164 | pop a 165 | or a, (3, x) 166 | ld (3, x), a ; CR1 not open drain 167 | jrt 00001$ 168 | 00090$: 169 | __endasm; 170 | } 171 | 172 | /****************************************************************************** 173 | * 174 | * Reset row pins 175 | * Set row pins to internal pull-up (leave as inputs) 176 | */ 177 | 178 | static void reset_rows(void) 179 | { 180 | __asm 181 | ldw y, _cfg_row 182 | 00001$: 183 | ld a, (2, y) ; pin mask 184 | jreq 00090$ 185 | ldw x, y 186 | addw y, #3 187 | ldw x, (x) ; base of port registers 188 | or a, (3, x) 189 | ld (3, x), a ; CR1 set internal pullup 190 | jrt 00001$ 191 | 00090$: 192 | __endasm; 193 | } 194 | 195 | /****************************************************************************** 196 | * 197 | * Check row for pressed key 198 | * in: (kcur points to next key mapping) 199 | * out: key or zero (zero flag valid) 200 | */ 201 | 202 | static char check_row(void) 203 | { 204 | __asm 205 | ldw y, _cfg_row 206 | 00001$: 207 | ld a, (2, y) ; pin mask 208 | jreq 00090$ 209 | ldw x, y 210 | addw y, #3 211 | ldw x, (x) ; base of port registers 212 | and a, (1, x) ; IDR 213 | jreq 00002$ ; bit clear, key pressed 214 | ldw x, _kcur 215 | incw x 216 | ldw _kcur, x 217 | jrt 00001$ 218 | 00002$: 219 | ldw x, _kcur 220 | ld a, (x) 221 | 00090$: 222 | __endasm; 223 | } 224 | 225 | /****************************************************************************** 226 | * 227 | * Check keypad for pressed key 228 | * out: key or zero (zero flag valid) 229 | */ 230 | 231 | static char check_key(void) 232 | { 233 | kcur = kmap; 234 | __asm 235 | ldw x, _cfg_col 236 | pushw x 237 | 00001$: 238 | ldw x, (1, sp) 239 | ld a, (2, x) 240 | jreq 00090$ 241 | ldw x, (x) 242 | cpl a 243 | and a, (x) 244 | ld (x), a 245 | call _check_row 246 | jrne 000090$ 247 | 248 | ldw x, (1, sp) 249 | addw x, #3 250 | ldw (1, sp), x 251 | subw x, #3 252 | ld a, (2, x) 253 | ldw x, (x) 254 | or a, (x) 255 | ld (x), a 256 | jrt 00001$ 257 | 258 | 000090$: 259 | addw sp, #2 260 | __endasm; 261 | } 262 | 263 | /****************************************************************************** 264 | * 265 | * This library scans the columns from left to right. Columns are outputs. 266 | * 267 | * The rows are input pins, set to use the internal pullup, so the scanning 268 | * column is low and the others are kept high. 269 | * 270 | * Only one key may be pressed at a time. 271 | */ 272 | -------------------------------------------------------------------------------- /lib_keypad.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_keypad.h 3 | * Date first: 10/11/2018 4 | * Date last: 10/14/2018 5 | * 6 | * Description: STM8 Library for simple keypad 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Size of keypad buffer 16 | */ 17 | #define KP_BUFSIZE 11 /* may be any arbitrary size */ 18 | 19 | #define KP_DEBOUNCE 40 /* debounce count in milliseconds */ 20 | #define KP_KEY_REL /* notify when key is released (bit-7 set) */ 21 | #define KP_POLL_MS 4 /* actual key polling rate, milliseconds */ 22 | 23 | /* 24 | * Keypad configuration 25 | * Rows and columns 26 | */ 27 | typedef struct { 28 | volatile char *reg_base; /* port ODR register */ 29 | char reg_mask; /* bit for row or column */ 30 | } KP_PIN; 31 | 32 | /* 33 | * Initialize 34 | * in: row config, column config 35 | */ 36 | void keypad_init(KP_PIN *, KP_PIN *); 37 | 38 | /* 39 | * Poll for keypad status 40 | * Call every millisecond 41 | * (profiling with Timer4 gives 36 uSec per poll) 42 | */ 43 | void keypad_poll(void); 44 | 45 | /* 46 | * Get key from keypad 47 | * out: key or zero (bit-7 set for key release) 48 | */ 49 | char keypad_getc(void); 50 | 51 | /* 52 | * Install alternate keypad map 53 | * in: new keypad map 54 | */ 55 | void keypad_kmap(char *); 56 | -------------------------------------------------------------------------------- /lib_lcd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_lcd.c 3 | * Date first: 12/19/2017 4 | * Date last: 09/22/2022 5 | * 6 | * Description: Library for Hitachi HD44780 LCDs on STM8 architecture. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018, 2022 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Pinouts: 16 | * 17 | * C4..C7 LCD D4..D7 (pins 11-14, fast) 18 | * C3 LCD Enable (pin 6, fast) 19 | * A3 LCD RS (pin 4) on STM8S_103 (fast pin) 20 | * F4 LCD RS (pin 4) on STM8S_105 (slow pin) 21 | * Vss LCD ground (pin 1) 22 | * Vdd LCD +5V (pin 2) 23 | * Vo LCD contrast (pin 3) 24 | * W* LCD R/W wired low (pin 5) 25 | */ 26 | 27 | #include "stm8s_header.h" 28 | #include "lib_delay.h" 29 | #include "lib_lcd.h" 30 | 31 | static void lcd_comd(char); 32 | static void lcd_data(char); 33 | static void lcd_nybble(char); 34 | 35 | #ifdef STM8103 36 | #define BUSY_COUNT 100 /* RC clock at 16mhz */ 37 | #define RS_PORT _PA_ODR 38 | #define RS_PIN 3 39 | #endif 40 | #ifdef STM8105 41 | #define RS_PORT _PF_ODR 42 | #define RS_PIN 4 43 | #warning "Pins C1 & C2 clobbered. Use as inputs." 44 | #define BUSY_COUNT 50 /* crystal oscillator at 8 mhz */ 45 | #endif 46 | 47 | //char busy_count = BUSY_COUNT; /* 100 uSecs */ 48 | 49 | /****************************************************************************** 50 | * 51 | * Set LCD cursor by line and column 52 | * 53 | * in: line (0-3), column (0-19) 54 | */ 55 | 56 | void lcd_curs(char line, char col) 57 | { 58 | #if __SDCCCALL == 0 59 | char val; 60 | 61 | val = col; 62 | if (line & 1) 63 | val += 0x40; /* lines 1 & 3 have 0x40 offset */ 64 | if (line & 2) 65 | val += 20; /* lines 2 & 3 have 20 offset */ 66 | lcd_comd(val | 0x80); 67 | #else /* Inline assembly due to bug in early SDCC 4.2 */ 68 | line, col; 69 | /* line will be in A register, col at (3, sp) */ 70 | __asm 71 | bcp a, #1 72 | jreq 00010$ 73 | add a, #0x40 74 | 00010$: 75 | bcp a, #2 76 | jreq 00011$ 77 | add a, #20 78 | 00011$: 79 | and a, #0xfc 80 | add a, (3, sp) 81 | or a, #0x80 82 | call _lcd_comd 83 | __endasm; 84 | #endif 85 | 86 | } 87 | 88 | /****************************************************************************** 89 | * 90 | * Write data byte to lcd 91 | */ 92 | 93 | void lcd_putc(char val) 94 | { 95 | val; 96 | __asm 97 | bset RS_PORT, #RS_PIN 98 | #if __SDCCCALL == 0 99 | ld a, (3, sp) 100 | #else 101 | push a 102 | #endif 103 | and a, #0xf0 104 | ld _PC_ODR, a 105 | bset _PC_ODR, #3 106 | call _delay_500ns 107 | bres _PC_ODR, #3 108 | 109 | #if __SDCCCALL == 0 110 | ld a, (3, sp) 111 | #else 112 | pop a 113 | #endif 114 | swap a 115 | and a, #0xf0 116 | ld _PC_ODR, a 117 | bset _PC_ODR, #3 118 | call _delay_500ns 119 | bres _PC_ODR, #3 120 | __endasm; 121 | delay_usecs(BUSY_COUNT); 122 | } 123 | 124 | void lcd_puts(char *s) 125 | { 126 | while (1) { 127 | if (*s == 0) 128 | return; 129 | lcd_putc(*s); 130 | s++; 131 | } 132 | } 133 | 134 | /****************************************************************************** 135 | * 136 | * Write command byte to lcd 137 | */ 138 | 139 | void lcd_comd(char val) 140 | { 141 | lcd_nybble(val); 142 | lcd_nybble(val << 4); 143 | delay_50us(); 144 | } 145 | 146 | /****************************************************************************** 147 | * 148 | * Write command nybble to lcd 149 | * in: nybble is high 4 bits 150 | */ 151 | 152 | void lcd_nybble(char val) 153 | { 154 | val; 155 | __asm 156 | bres RS_PORT, #RS_PIN 157 | #if __SDCCCALL == 0 158 | ld a, (3, sp) 159 | #endif 160 | and a, #0xf0 161 | ld _PC_ODR, a 162 | call _delay_500ns 163 | bset _PC_ODR, #3 164 | call _delay_500ns 165 | bres _PC_ODR, #3 166 | __endasm; 167 | } 168 | 169 | /****************************************************************************** 170 | * 171 | * Initialize LCD 172 | */ 173 | 174 | void lcd_init(void) 175 | { 176 | PC_DDR |= 0xf8; /* C3, C4-C7 outputs */ 177 | PC_CR1 |= 0xf8; 178 | PC_CR2 |= 0xf8; /* fast outputs */ 179 | #ifdef STM8103 180 | PA_DDR |= 0x08; /* A3 output */ 181 | PA_CR1 |= 0x08; 182 | PA_CR2 |= 0x08; 183 | #endif 184 | #ifdef STM8105 185 | PF_DDR = 0x10; 186 | PF_CR1 = 0x10; 187 | #endif 188 | delay_ms(50); 189 | lcd_nybble(0x30); /* start with 8-bit mode */ 190 | delay_ms(5); /* more than 4.1 ms */ 191 | lcd_nybble(0x30); 192 | delay_usecs(120); /* more than 100 us */ 193 | lcd_nybble(0x30); 194 | delay_usecs(50); /* more than 37 us */ 195 | lcd_nybble(0x20); /* set to 4-bit mode */ 196 | delay_usecs(50); 197 | 198 | lcd_comd(0x28); /* 4-bit mode, 2 lines */ 199 | lcd_comd(0x0e); /* turn on diplay and cursor */ 200 | lcd_comd(0x06); /* auto increment and move cursor */ 201 | } 202 | 203 | /****************************************************************************** 204 | * 205 | * Following addition contributed by jackkum August 2019 206 | * 207 | * Clear the LCD 208 | */ 209 | 210 | void lcd_clear(void) { 211 | lcd_comd(LCD_CLEARDISPLAY); 212 | } 213 | 214 | /* 215 | * Set LCD MODE 216 | */ 217 | 218 | void lcd_mode(char mode) { 219 | lcd_comd(LCD_DISPLAYCONTROL | mode); 220 | } 221 | 222 | -------------------------------------------------------------------------------- /lib_lcd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_lcd.h 3 | * Date first: 12/31/2017 4 | * Date last: 08/07/2019 5 | * 6 | * Description: Library for Hitachi HD44780 LCD on STM8 architecture. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize LCD 16 | */ 17 | 18 | void lcd_init(void); 19 | 20 | /* 21 | * Set LCD cursor position by line and column 22 | * in: line (0-3), column (0-19) 23 | */ 24 | 25 | void lcd_curs(char, char); 26 | 27 | /* 28 | * Write character to LCD (and alias function) 29 | */ 30 | 31 | void lcd_putc(char); 32 | 33 | /* 34 | * Write string to LCD (zero terminated) 35 | */ 36 | 37 | void lcd_puts(char *); 38 | 39 | /* 40 | * Following addition contributed by jackkum August 2019 41 | */ 42 | 43 | /* 44 | * Clear lcd 45 | */ 46 | void lcd_clear(void); 47 | 48 | /* 49 | * Mode of lcd 50 | */ 51 | void lcd_mode(char mode); 52 | 53 | 54 | // commands 55 | #define LCD_CLEARDISPLAY 0x01 56 | #define LCD_RETURNHOME 0x02 57 | #define LCD_ENTRYMODESET 0x04 58 | #define LCD_DISPLAYCONTROL 0x08 59 | #define LCD_CURSORSHIFT 0x10 60 | #define LCD_FUNCTIONSET 0x20 61 | #define LCD_SETCGRAMADDR 0x40 62 | #define LCD_SETDDRAMADDR 0x80 63 | 64 | // flags for display entry mode 65 | #define LCD_ENTRYRIGHT 0x00 66 | #define LCD_ENTRYLEFT 0x02 67 | #define LCD_ENTRYSHIFTINCREMENT 0x01 68 | #define LCD_ENTRYSHIFTDECREMENT 0x00 69 | 70 | // flags for display on/off control 71 | #define LCD_DISPLAYON 0x04 72 | #define LCD_DISPLAYOFF 0x00 73 | #define LCD_CURSORON 0x02 74 | #define LCD_CURSOROFF 0x00 75 | #define LCD_BLINKON 0x01 76 | #define LCD_BLINKOFF 0x00 77 | 78 | // flags for display/cursor shift 79 | #define LCD_DISPLAYMOVE 0x08 80 | #define LCD_CURSORMOVE 0x00 81 | #define LCD_MOVERIGHT 0x04 82 | #define LCD_MOVELEFT 0x00 83 | 84 | // flags for function set 85 | #define LCD_8BITMODE 0x10 86 | #define LCD_4BITMODE 0x00 87 | #define LCD_2LINE 0x08 88 | #define LCD_1LINE 0x00 89 | #define LCD_5x10DOTS 0x04 90 | #define LCD_5x8DOTS 0x00 91 | 92 | 93 | -------------------------------------------------------------------------------- /lib_log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_log.c 3 | * Date first: 03/26/2018 4 | * Date last: 10/16/2018 5 | * 6 | * Description: Library for using a many entry system log 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Note: This system log library uses the Timer4 clock library to 16 | * save the current clock as timestamps. 17 | */ 18 | 19 | #include "stm8s_header.h" 20 | 21 | #include "lib_log.h" 22 | #include "lib_clock.h" 23 | #include "lib_eeprom.h" 24 | #include "lib_flash.h" 25 | 26 | static LOG_ENTRY *log_base; 27 | static LOG_ENTRY *log_end; 28 | static LOG_ENTRY *log_old; /* oldest log entry */ 29 | static LOG_ENTRY *log_new; /* newest log entry */ 30 | 31 | static int log_size; /* number bytes in each entry */ 32 | static short log_count; /* number of log entries */ 33 | 34 | static long log_stamp; 35 | 36 | static void (*mem_lock)(void); 37 | static char (*mem_unlock)(void); 38 | 39 | /****************************************************************************** 40 | * 41 | * Initialize the system log 42 | * in: base address, number of enties 43 | */ 44 | 45 | void log_init(char *base, short count) 46 | { 47 | LOG_ENTRY *old, *new, *ptr; 48 | short i; 49 | 50 | log_base = (LOG_ENTRY *)base; 51 | log_end = log_base + count; 52 | log_count = count; 53 | log_size = sizeof(LOG_ENTRY); 54 | log_stamp = 0; 55 | 56 | old = log_base; 57 | new = log_base; 58 | ptr = log_base; 59 | 60 | for (i = 0; i < count; i++) { 61 | ptr++; 62 | if (!ptr->stamp) 63 | continue; 64 | if (old->stamp > ptr->stamp) 65 | old = ptr; 66 | if (log_stamp < ptr->stamp) { 67 | log_stamp = ptr->stamp; 68 | new = ptr; 69 | } 70 | } 71 | log_stamp++; 72 | log_old = old; 73 | log_new = new; 74 | 75 | if (((short)base > 0x8000)) { 76 | mem_lock = flash_lock; 77 | mem_unlock = flash_unlock; 78 | } 79 | else { 80 | mem_lock = eeprom_lock; 81 | mem_unlock = eeprom_unlock; 82 | } 83 | } 84 | 85 | /****************************************************************************** 86 | * 87 | * Erase all log entries 88 | */ 89 | void log_erase(void) 90 | { 91 | char *ptr, zero[4]; 92 | short i; 93 | 94 | zero[0] = 0; 95 | zero[1] = 0; 96 | zero[2] = 0; 97 | zero[3] = 0; 98 | 99 | ptr = (char *)log_base; 100 | i = log_count; 101 | 102 | if (!mem_unlock()) 103 | return; 104 | while (i) { 105 | eeprom_word(zero, ptr); 106 | ptr += 4; 107 | eeprom_word(zero, ptr); 108 | ptr += 4; 109 | i--; 110 | } 111 | mem_lock(); 112 | log_stamp = 0; 113 | log_old = log_base; 114 | log_new = log_base; 115 | } 116 | 117 | /****************************************************************************** 118 | * 119 | * Write new log entry 120 | * in: event type 121 | * out: zero = success 122 | */ 123 | char log_write(char type) 124 | { 125 | LOG_ENTRY entry; 126 | char binary[4], *src, *dst; 127 | 128 | clock_bin_get(binary); 129 | entry.stamp = log_stamp; 130 | entry.type = type; 131 | entry.clock_h = binary[1]; 132 | entry.clock_m = binary[2]; 133 | entry.clock_s = binary[3]; 134 | 135 | if (!mem_unlock()) 136 | return 1; 137 | 138 | log_new++; 139 | if (log_new == log_end) 140 | log_new = log_base; 141 | if (log_new == log_old) { 142 | log_old++; 143 | if (log_old == log_end) 144 | log_old = log_base; 145 | } 146 | dst = (char *)log_new; 147 | src = (char *)&entry; 148 | 149 | eeprom_word(src, dst); 150 | eeprom_word(src + 4, dst + 4); 151 | mem_lock(); 152 | 153 | return 0; 154 | } 155 | 156 | /****************************************************************************** 157 | * 158 | * Advance log timestamp 159 | */ 160 | 161 | void log_second(void) 162 | { 163 | __asm 164 | ldw x, _log_stamp+2 165 | incw x 166 | ldw _log_stamp+2, x 167 | jreq 00001$ 168 | ret 169 | 00001$: 170 | ldw x, _log_stamp+0 171 | incw x 172 | ldw _log_stamp+0, x 173 | ret 174 | __endasm; 175 | } 176 | 177 | /****************************************************************************** 178 | * 179 | * Scan all log entries 180 | * in: callback function for each entry 181 | */ 182 | 183 | void log_scan(void (*callback)(LOG_ENTRY *)) 184 | { 185 | LOG_ENTRY *entry; 186 | 187 | entry = log_old; 188 | while (1) { 189 | if (entry->stamp) 190 | callback(entry); 191 | entry++; 192 | if (entry == log_end) 193 | entry = log_base; 194 | if (entry == log_old) 195 | break; 196 | } 197 | } 198 | 199 | /****************************************************************************** 200 | * 201 | * Get count of valid log entries 202 | */ 203 | 204 | short log_valid(void) 205 | { 206 | LOG_ENTRY *entry; 207 | short count; 208 | 209 | entry = log_base; 210 | count = 0; 211 | 212 | while (entry != log_end) { 213 | if (entry->stamp) 214 | count++; 215 | entry++; 216 | } 217 | return count; 218 | } 219 | 220 | /****************************************************************************** 221 | * 222 | * Do EEPROM word write 223 | */ 224 | 225 | void eeprom_word(char *src, char *dst) 226 | { 227 | src, dst; 228 | __asm 229 | bset _FLASH_CR2, #6 230 | bres _FLASH_NCR2, #6 231 | ldw x, (3, sp) 232 | ldw y, (5, sp) 233 | push #4 234 | 00001$: 235 | ld a, (x) 236 | ld (y), a 237 | incw x 238 | incw y 239 | dec (1, sp) 240 | jrne 00001$ 241 | pop a 242 | __endasm; 243 | } 244 | -------------------------------------------------------------------------------- /lib_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_log.h 3 | * Date first: 03/26/2018 4 | * Date last: 08/21/2018 5 | * 6 | * Description: Library for maintaining a many entry system log 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Log entry 16 | */ 17 | 18 | typedef struct { 19 | unsigned long stamp; /* non-zero, unique timestamp */ 20 | char type; /* entry type */ 21 | char clock_h; /* clock hour */ 22 | char clock_m; /* clock minute */ 23 | char clock_s; /* clock second */ 24 | } LOG_ENTRY; 25 | 26 | /* 27 | * Initialize the log library 28 | * in: base address, number of entries 29 | */ 30 | void log_init(char *, short); 31 | 32 | /* 33 | * Advance log timestamp 34 | * (call every second) 35 | */ 36 | void log_second(void); 37 | 38 | /* 39 | * Erase all log entries 40 | */ 41 | void log_erase(void); 42 | 43 | /* 44 | * Write new log entry 45 | * in: event type 46 | * out: zero = success 47 | */ 48 | char log_write(char); 49 | 50 | /* 51 | * Scan all log entries 52 | * in: callback function for each entry 53 | */ 54 | 55 | void log_scan(void (*callback)(LOG_ENTRY *)); 56 | 57 | /* 58 | * Get count of valid log entries 59 | */ 60 | short log_valid(void); 61 | 62 | /* 63 | * Write word to EEPROM 64 | * in: source, dest 65 | */ 66 | 67 | void eeprom_word(char *, char *); 68 | -------------------------------------------------------------------------------- /lib_m9800.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_m9800.c 3 | * Date first: 05/23/2018 4 | * Date last: 05/24/2018 5 | * 6 | * Description: Library for reading temperature from Microchip MCP9800 device. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | #include "stm8s_header.h" 17 | 18 | #include "lib_i2c.h" 19 | #include "lib_m9800.h" 20 | 21 | #define I2C_ADDR 7 /* from address pins a0, a1, a2 */ 22 | #define I2C_DEV_ADDR (0x90 | (I2C_ADDR << 1)) 23 | 24 | #define CONFIG_VAL 0x60 /* continuous conversion, max precision */ 25 | 26 | #define REG_TEMP 0 27 | #define REG_CONFIG 1 28 | #define REG_HYSTERESIS 2 29 | #define REG_TEMP_LIMIT 3 30 | 31 | /****************************************************************************** 32 | * 33 | * Initialize 34 | * out: zero = success 35 | */ 36 | 37 | char m9800_init(void) 38 | { 39 | i2c_start(); 40 | i2c_txbit8(I2C_DEV_ADDR); 41 | if (!i2c_getack()) { 42 | i2c_stop(); 43 | return 1; 44 | } 45 | i2c_txbit8(REG_CONFIG); 46 | i2c_getack(); 47 | i2c_txbit8(CONFIG_VAL); 48 | i2c_stop(); 49 | return 0; 50 | } 51 | 52 | /****************************************************************************** 53 | * 54 | * Get current temperature 55 | * out: 13-bit signed value, degrees C * 16 56 | */ 57 | 58 | short m9800_temp(void) 59 | { 60 | short temp; 61 | char val; 62 | 63 | temp = 0; 64 | 65 | i2c_start(); 66 | i2c_txbit8(I2C_DEV_ADDR); 67 | if (!i2c_getack()) 68 | goto quit; 69 | i2c_txbit8(REG_TEMP); 70 | if (!i2c_getack()) 71 | goto quit; 72 | i2c_stop(); 73 | 74 | i2c_start(); 75 | i2c_txbit8(I2C_DEV_ADDR | 1); 76 | if (!i2c_getack()) 77 | goto quit; 78 | i2c_data1(); /* release control of data pin */ 79 | 80 | val = i2c_rxbit8(); 81 | temp = val << 8; 82 | i2c_sendack(); 83 | 84 | val = i2c_rxbit8(); 85 | temp |= val; 86 | i2c_sendnak(); 87 | quit: 88 | i2c_stop(); 89 | 90 | return temp >> 4; /* note: signed shift */ 91 | } 92 | 93 | -------------------------------------------------------------------------------- /lib_m9800.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_m9800.h 3 | * Date first: 05/23/2018 4 | * Date last: 05/23/2018 5 | * 6 | * Description: Library for reading temperature from Microchip MCP9800 device. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize 16 | * out: zero = success 17 | */ 18 | 19 | char m9800_init(void); 20 | 21 | /* 22 | * Get current temperature 23 | * out: 13-bit signed value, degrees C * 16 24 | */ 25 | 26 | short m9800_temp(void); 27 | -------------------------------------------------------------------------------- /lib_max6675.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_max6675.c 3 | * Date first: 12/12/2022 4 | * Date last: 12/12/2022 5 | * 6 | * Description: STM8 Library for MAX6675 thermocouple converter. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2022 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Includes 16 | */ 17 | 18 | #include "stm8s_header.h" 19 | #include "lib_max6675.h" 20 | #include 21 | 22 | /****************************************************************************** 23 | * 24 | * This chip has a very simple SPI interface, and a basic CS*, clock & data, 25 | * so a basic read function will be used. 26 | * 27 | * D3: SPI clock (out) 28 | * A1: SPI in (MISO) 29 | * A2: CS* (slow pin) 30 | */ 31 | 32 | static uint16_t read16(void); 33 | 34 | /****************************************************************************** 35 | * 36 | * Initialize device 37 | */ 38 | 39 | void max6675_init(void) 40 | { 41 | PA_DDR |= 0x04; /* A2 is output. */ 42 | PA_ODR &= 0x04; /* A2 *CS is active low. */ 43 | PA_CR1 |= 0x06; /* A2 is push-pull, A1 has pullup. */ 44 | 45 | PD_DDR |= 0x08; /* D3 is output. */ 46 | PD_CR1 = 0x08; /* D3 push-pull. */ 47 | PD_CR2 |= 0x08; /* D3 is high speed. */ 48 | } 49 | 50 | /****************************************************************************** 51 | * 52 | * Get current thermocouple temperature. 53 | * out: temperature in 0.25 degrees C (0 to < 1024) or MAX6675_ERROR 54 | */ 55 | 56 | int16_t max6675_read(void) 57 | { 58 | uint16_t result; 59 | 60 | result = read16(); 61 | if (result & 0x04) /* Thermocouple not connected. */ 62 | return MAX6675_ERROR; 63 | result >>= 3; 64 | return result; 65 | } 66 | 67 | /* MAX6675 timing: 68 | * 69 | * 4.3mhz max clock frequency. 70 | * 100nS min clock high, clock low. 71 | * 100nS min *CS to clock rise. 72 | * 100nS min clock fall to data valid. 73 | * 74 | * Note: First data bit (D15) is always low and appears on fall of CS*. 75 | * 76 | ****************************************************************************** 77 | * 78 | * Read 16-bit result 79 | * out: encoded result (0ttttttttttttE0?), t=temp bit, E=error 80 | */ 81 | 82 | static uint16_t read16(void) 83 | #pragma disable_warning 59 84 | { 85 | __asm 86 | bres _PA_ODR, #2 /* CS* low */ 87 | push #16 88 | 00001$: 89 | btjt _PA_IDR, #1, 00002$ /* Get bit into carry. */ 90 | 00002$: 91 | rlcw x 92 | bset _PD_ODR, #3 /* Clock high. */ 93 | nop /* To meet 100nS clock high time. */ 94 | bres _PD_ODR, #3 /* Clock low. */ 95 | dec (1, sp) 96 | jrne 00001$ 97 | add sp, #1 98 | bset _PA_ODR, #2 /* CS* high */ 99 | __endasm; 100 | } 101 | -------------------------------------------------------------------------------- /lib_max6675.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_max6675.h 3 | * Date first: 12/12/2022 4 | * Date last: 12/12/2022 5 | * 6 | * Description: STM8 Library for MAX6675 thermocouple converter. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2022 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Types 16 | */ 17 | #include 18 | 19 | /* 20 | * Initialize device 21 | */ 22 | 23 | void max6675_init(void); 24 | 25 | /* 26 | * Get current thermocouple temperature. 27 | * out: temperature in 0.25 degrees C or MAX6675_ERROR 28 | */ 29 | 30 | int16_t max6675_read(void); 31 | 32 | #define MAX6675_ERROR (0x8000) 33 | -------------------------------------------------------------------------------- /lib_max7219.font: -------------------------------------------------------------------------------- 1 | /* 5x7 LCD font copied from: 2 | * https://fontstruct.com/fontstructions/show/310233/5x8_lcd_hd44780u_a02 3 | * This appears to be lifted from the Hitachi HD44780 internal font. 4 | * 5 | * The bits are left to right, low bit on top and bit-7 on the bottom. 6 | */ 7 | #ifdef MAX7219_DOT /* comment out in lib_max7219.h if dot matrix LED not used */ 8 | 9 | const char font_map[96*5] = { 10 | 0x00, 0x00, 0x00, 0x00, 0x00,// 0x20 (Space) 11 | 0x00, 0x00, 0x9E, 0x00, 0x00,// 0x21 ! 12 | 0x00, 0x0E, 0x00, 0x0E, 0x00,// 0x22 " 13 | 0x28, 0xFE, 0x28, 0xFE, 0x28,// 0x23 # 14 | 0x48, 0x54, 0xFE, 0x54, 0x24,// 0x24 $ 15 | 0x46, 0x26, 0x10, 0xC8, 0xC4,// 0x25 % 16 | 0x6C, 0x92, 0xAA, 0x44, 0xA0,// 0x26 & 17 | 0x00, 0x0A, 0x06, 0x00, 0x00,// 0x27 ' 18 | 0x00, 0x38, 0x44, 0x82, 0x00,// 0x28 ( 19 | 0x00, 0x82, 0x44, 0x38, 0x00,// 0x29 ) 20 | 0x10, 0x54, 0x38, 0x54, 0x10,// 0x2A * 21 | 0x10, 0x10, 0x7C, 0x10, 0x10,// 0x2B + 22 | 0x00, 0xA0, 0x60, 0x00, 0x00,// 0x2C , 23 | 0x10, 0x10, 0x10, 0x10, 0x10,// 0x2D - 24 | 0x00, 0x60, 0x60, 0x00, 0x00,// 0x2E . 25 | 0x40, 0x20, 0x10, 0x08, 0x04,// 0x2F / 26 | 0x7C, 0xA2, 0x92, 0x8A, 0x7C,// 0x30 0 27 | 0x00, 0x84, 0xFE, 0x80, 0x00,// 0x31 1 28 | 0x84, 0xC2, 0xA2, 0x92, 0x8C,// 0x32 2 29 | 0x42, 0x82, 0x8A, 0x96, 0x62,// 0x33 3 30 | 0x30, 0x28, 0x24, 0xFE, 0x20,// 0x34 4 31 | 0x4E, 0x8A, 0x8A, 0x8A, 0x72,// 0x35 5 32 | 0x78, 0x94, 0x92, 0x92, 0x60,// 0x36 6 33 | 0x02, 0xE2, 0x12, 0x0A, 0x06,// 0x37 7 34 | 0x6C, 0x92, 0x92, 0x92, 0x6C,// 0x38 8 35 | 0x0C, 0x92, 0x92, 0x52, 0x3C,// 0x39 9 36 | 0x00, 0x6C, 0x6C, 0x00, 0x00,// 0x3A : 37 | 0x00, 0xAC, 0x6C, 0x00, 0x00,// 0x3B ; 38 | 0x00, 0x10, 0x28, 0x44, 0x82,// 0x3C < 39 | 0x28, 0x28, 0x28, 0x28, 0x28,// 0x3D = 40 | 0x82, 0x44, 0x28, 0x10, 0x00,// 0x3E > 41 | 0x04, 0x02, 0xA2, 0x12, 0x0C,// 0x3F ? 42 | 0x64, 0x92, 0xF2, 0x82, 0x7C,// 0x40 @ 43 | 0xFC, 0x22, 0x22, 0x22, 0xFC,// 0x41 A 44 | 0xFE, 0x92, 0x92, 0x92, 0x6C,// 0x42 B 45 | 0x7C, 0x82, 0x82, 0x82, 0x44,// 0x43 C 46 | 0xFE, 0x82, 0x82, 0x44, 0x38,// 0x44 D 47 | 0xFE, 0x92, 0x92, 0x92, 0x82,// 0x45 E 48 | 0xFE, 0x12, 0x12, 0x02, 0x02,// 0x46 F 49 | 0x7C, 0x82, 0x82, 0xA2, 0x64,// 0x47 G 50 | 0xFE, 0x10, 0x10, 0x10, 0xFE,// 0x48 H 51 | 0x00, 0x82, 0xFE, 0x82, 0x00,// 0x49 I 52 | 0x40, 0x80, 0x82, 0x7E, 0x02,// 0x4A J 53 | 0xFE, 0x10, 0x28, 0x44, 0x82,// 0x4B K 54 | 0xFE, 0x80, 0x80, 0x80, 0x80,// 0x4C L 55 | 0xFE, 0x04, 0x08, 0x04, 0xFE,// 0x4D M 56 | 0xFE, 0x08, 0x10, 0x20, 0xFE,// 0x4E N 57 | 0x7C, 0x82, 0x82, 0x82, 0x7C,// 0x4F O 58 | 0xFE, 0x12, 0x12, 0x12, 0x0C,// 0x50 P 59 | 0x7C, 0x82, 0xA2, 0x42, 0xBC,// 0x51 Q 60 | 0xFE, 0x12, 0x32, 0x52, 0x8C,// 0x52 R 61 | 0x8C, 0x92, 0x92, 0x92, 0x62,// 0x53 S 62 | 0x02, 0x02, 0xFE, 0x02, 0x02,// 0x54 T 63 | 0x7E, 0x80, 0x80, 0x80, 0x7E,// 0x55 U 64 | 0x3E, 0x40, 0x80, 0x40, 0x3E,// 0x56 V 65 | 0xFE, 0x40, 0x30, 0x40, 0xFE,// 0x57 W 66 | 0xC6, 0x28, 0x10, 0x28, 0xC6,// 0x58 X 67 | 0x06, 0x08, 0xF0, 0x08, 0x06,// 0x59 Y 68 | 0xC2, 0xA2, 0x92, 0x8A, 0x86,// 0x5A Z 69 | 0x00, 0x00, 0xFE, 0x82, 0x82,// 0x5B [ 70 | 0x04, 0x08, 0x10, 0x20, 0x40,// 0x5C " 71 | 0x82, 0x82, 0xFE, 0x00, 0x00,// 0x5D ] 72 | 0x08, 0x04, 0x02, 0x04, 0x08,// 0x5E ^ 73 | 0x80, 0x80, 0x80, 0x80, 0x80,// 0x5F _ 74 | 0x00, 0x02, 0x04, 0x08, 0x00,// 0x60 ` 75 | 0x40, 0xA8, 0xA8, 0xA8, 0xF0,// 0x61 a 76 | 0xFE, 0x90, 0x88, 0x88, 0x70,// 0x62 b 77 | 0x70, 0x88, 0x88, 0x88, 0x40,// 0x63 c 78 | 0x70, 0x88, 0x88, 0x90, 0xFE,// 0x64 d 79 | 0x70, 0xA8, 0xA8, 0xA8, 0x30,// 0x65 e 80 | 0x10, 0xFC, 0x12, 0x02, 0x04,// 0x66 f 81 | 0x10, 0x28, 0xA8, 0xA8, 0x78,// 0x67 g 82 | 0xFE, 0x10, 0x08, 0x08, 0xF0,// 0x68 h 83 | 0x00, 0x88, 0xFA, 0x80, 0x00,// 0x69 i 84 | 0x40, 0x80, 0x88, 0x7A, 0x00,// 0x6A j 85 | 0x00, 0xFE, 0x20, 0x50, 0x88,// 0x6B k 86 | 0x00, 0x82, 0xFE, 0x80, 0x00,// 0x6C l 87 | 0xF8, 0x08, 0x30, 0x08, 0xF0,// 0x6D m 88 | 0xF8, 0x10, 0x08, 0x08, 0xF0,// 0x6E n 89 | 0x70, 0x88, 0x88, 0x88, 0x70,// 0x6F o 90 | 0xF8, 0x28, 0x28, 0x28, 0x10,// 0x70 p 91 | 0x10, 0x28, 0x28, 0x30, 0xF8,// 0x71 q 92 | 0xF8, 0x10, 0x08, 0x08, 0x10,// 0x72 r 93 | 0x90, 0xA8, 0xA8, 0xA8, 0x40,// 0x73 s 94 | 0x08, 0x7E, 0x88, 0x80, 0x40,// 0x74 t 95 | 0x78, 0x80, 0x80, 0x40, 0xF8,// 0x75 u 96 | 0x38, 0x40, 0x80, 0x40, 0x38,// 0x76 v 97 | 0x78, 0x80, 0x60, 0x80, 0x78,// 0x77 w 98 | 0x88, 0x50, 0x20, 0x50, 0x88,// 0x78 x 99 | 0x18, 0xA0, 0xA0, 0xA0, 0x78,// 0x79 y 100 | 0x88, 0xC8, 0xA8, 0x98, 0x88,// 0x7A z 101 | 0x00, 0x10, 0x6C, 0x82, 0x00,// 0x7B { 102 | 0x00, 0x00, 0xFE, 0x00, 0x00,// 0x7C | 103 | 0x00, 0x82, 0x6C, 0x10, 0x00,// 0x7D } 104 | 0x20, 0x10, 0x10, 0x20, 0x10,// 0x7E 105 | 0xF0, 0x88, 0x84, 0x88, 0xF0,// 0x7F 106 | }; 107 | #endif /* MAX7219_DOT */ 108 | -------------------------------------------------------------------------------- /lib_max7219.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_max7219.h 3 | * Date first: 02/27/2018 4 | * Date last: 12/13/2022 5 | * 6 | * Description: STM8 Library for MAX7219 LED array. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Initialize array 16 | * in: type, device count 17 | */ 18 | 19 | void m7219_init(char, char); 20 | 21 | #define MAX7219_7SEG 1 /* 8 7-segment LEDs */ 22 | #define MAX7219_DOT 2 /* 8x8 LED matrix(es), using 5x8 font */ 23 | #define MAX7219_GRAPH 3 /* 8x8 LED matrix(es), sending graphics */ 24 | 25 | /* Comment out or erase the definition for MAX7219_DOT if you don't use 26 | * the font bitmap. The font uses 480 bytes of program memory. 27 | * Both MAX7219_DOT and MAX7219_GRAPH use an extra 9 bytes of RAM. 28 | * Graphics are bit columns, left to right, lowest bit on top, bit-7 on bottom. 29 | */ 30 | 31 | /* 32 | * Write digit/char to unit 33 | * in: digit/char (ASCII)/graphic. If 7SEG, bit-7 is decimal point 34 | */ 35 | 36 | void m7219_putc(char); 37 | 38 | /* 39 | * Write number/ASCII string to unit 40 | * in: string (Note: for graphics, zero is valid, so use m7219_putc() instead) 41 | */ 42 | 43 | void m7219_puts(const char *); 44 | 45 | /* 46 | * Set cursor position 47 | * in: line or device# (0-max), column 48 | */ 49 | 50 | void m7219_curs(char, char); 51 | 52 | /* 53 | * Clear all displays 54 | */ 55 | 56 | void m7219_clear(void); 57 | 58 | /* 59 | * Set LED intensity 60 | * in: 0 (minimum) to 15 (maximum) 61 | */ 62 | 63 | void m7219_bright(char); 64 | 65 | /* 66 | * Set LED options 67 | */ 68 | 69 | void m7219_option(char); 70 | 71 | #define MAX7219_WRAP 1 /* wrap around to first row & column */ 72 | #define MAX7219_NOWRAP 2 /* don't wrap, ignore extra data */ 73 | #define MAX7219_MARQUEE 3 /* begin marquee: don't show until wrap */ 74 | 75 | #define MAX7219_PRERENDER /* Render into pixel buffer. */ 76 | 77 | #ifdef MAX7219_PRERENDER 78 | /* 79 | * Pre-render text into a raw pixel buffer instead of sending to the 80 | * displays. This will make sending the pixels much faster. The buffer size 81 | * is 8 bytes for every MAX7219 device (the 8x32 module has 4). The "skip" 82 | * count is the number of left pixels to omit from the first character. 83 | * This is for making a moving marquee. 84 | * 85 | * in: pixel buffer, pixels to skip 86 | */ 87 | void m7219_prerender(char *, char); 88 | 89 | /* 90 | * Send pre-rendered pixel buffer to displays. 91 | * 92 | * in: pixel buffer 93 | */ 94 | void m7219_sendbuf(char *); 95 | 96 | #endif /* MAX7219_PRERENDER */ 97 | -------------------------------------------------------------------------------- /lib_ping.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_ping.c 3 | * Date first: 11/04/2018 4 | * Date last: 12/04/2018 5 | * 6 | * Description: STM8 Library for HC-SR04 ultrasonic range finder. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "stm8s_header.h" 18 | #include "lib_ping.h" 19 | 20 | typedef struct { 21 | IO_CALL_INT *cfg; /* output pin and callback function */ 22 | char *count; /* high latch count */ 23 | char *pol_addr; /* register with polarity bit */ 24 | char pol_mask; /* polarity bit */ 25 | int start; /* pulse start */ 26 | char ping_hi; /* high 8 bits of start */ 27 | } PING_DATA; 28 | 29 | static PING_DATA ping_data[3]; 30 | 31 | static char active; /* channel active flags */ 32 | 33 | static char clock_hi; /* make 24 bits for timer2 */ 34 | 35 | static PING_DATA *get_data(char); 36 | static void do_trigger(volatile char *, char); 37 | 38 | #pragma disable_warning 59 39 | 40 | /****************************************************************************** 41 | * 42 | * Initialize 43 | * in: Timer2 channel(s), list of pin/callback config 44 | */ 45 | 46 | void ping_init(char chans, IO_CALL_INT *cfg) 47 | { 48 | clock_hi = 0; 49 | active = 0; 50 | 51 | #ifdef PING_USE_C1 52 | if (chans & PING_CHAN1) { 53 | ping_data[0].cfg = cfg; 54 | ping_data[0].count = &TIM2_CCR1H; 55 | ping_data[0].pol_addr = &TIM2_CCER1; 56 | ping_data[0].pol_mask = 0x02; 57 | cfg++; 58 | __asm 59 | bset _active, #1 60 | bset _TIM2_IER, #1 61 | bset _TIM2_EGR, #1 62 | mov _TIM2_CCMR1, #0x31 63 | bset _TIM2_CCER1, #0 64 | __endasm; 65 | } 66 | #endif 67 | #ifdef PING_USE_C2 68 | if (chans & PING_CHAN2) { 69 | ping_data[1].cfg = cfg; 70 | ping_data[1].count = &TIM2_CCR2H; 71 | ping_data[1].pol_addr = &TIM2_CCER1; 72 | ping_data[1].pol_mask = 0x20; 73 | cfg++; 74 | __asm 75 | bset _active, #2 76 | bset _TIM2_IER, #2 77 | bset _TIM2_EGR, #2 78 | mov _TIM2_CCMR2, #0x31 79 | bset _TIM2_CCER1, #4 80 | __endasm; 81 | } 82 | #endif 83 | #ifdef PING_USE_C3 84 | if (chans & PING_CHAN3) { 85 | ping_data[2].cfg = cfg; 86 | ping_data[2].count = &TIM2_CCR3H; 87 | ping_data[2].pol_addr = &TIM2_CCER2; 88 | ping_data[2].pol_mask = 0x02; 89 | __asm 90 | bset _active, #3 91 | bset _TIM2_IER, #3 92 | bset _TIM2_EGR, #3 93 | mov _TIM2_CCMR3, #0x31 94 | bset _TIM2_CCER2, #0 95 | __endasm; 96 | } 97 | #endif 98 | __asm 99 | bset _TIM2_IER, #0 /* interrupt on clock */ 100 | __endasm; 101 | #ifdef STM8103 102 | TIM2_PSCR = 4; /* prescale = 16, 1 uSec per count */ 103 | #endif 104 | #ifdef STM8105 105 | TIM2_PSCR = 3; /* prescale = 8 */ 106 | #endif 107 | TIM2_CR1 = 1; /* counter enable */ 108 | } 109 | 110 | /****************************************************************************** 111 | * 112 | * Get ping data block from channel 113 | * in: Channel 114 | * out: data block 115 | */ 116 | 117 | static PING_DATA *get_data(char chan) 118 | { 119 | if (chan == PING_CHAN1) 120 | return (ping_data + 0); 121 | if (chan == PING_CHAN2) 122 | return (ping_data + 1); 123 | return (ping_data + 2); 124 | } 125 | 126 | /****************************************************************************** 127 | * 128 | * Start ping process (ping may take up to 20ms to complete) 129 | * in: Channel (PING_CHAN1/2/3) 130 | */ 131 | 132 | void ping_send(char chan) 133 | { 134 | PING_DATA *data; 135 | IO_PIN *pin; 136 | 137 | data = get_data(chan); 138 | pin = data->cfg->pin; 139 | 140 | /* set polarity to capture & interrupt on rising edge */ 141 | *(data->pol_addr) &= ~(data->pol_mask); 142 | 143 | do_trigger(pin->reg_base, pin->reg_mask); 144 | } 145 | 146 | static void do_trigger(volatile char *base, char mask) 147 | { 148 | base, mask; 149 | __asm 150 | ldw x, (3, sp) 151 | ld a, (5, sp) 152 | or a, (x) 153 | ld (x), a 154 | 155 | push #10 156 | call _delay_usecs 157 | pop a 158 | 159 | ldw x, (3, sp) 160 | ld a, (5, sp) 161 | xor a, (x) 162 | ld (x), a 163 | __endasm; 164 | } 165 | 166 | /****************************************************************************** 167 | * 168 | * Channel 1/2/3 interrupt 169 | * 170 | * If rising edge, the ping is starting. Save the current time. 171 | * If falling edge, the ping has returned. Subtract the start time to 172 | * get the round trip time and call the callback function to give it 173 | * the information. 174 | * 175 | * in: X has channel data structure (non-standard call) 176 | */ 177 | 178 | static void isr_chan(PING_DATA *data) 179 | { 180 | data; 181 | __asm 182 | ldw y, x ; channel data structure 183 | ldw x, (7, x) ; get pulse start 184 | pushw x 185 | 186 | ldw x, y 187 | ldw x, (2, x) ; latch count pointer 188 | ld a, (x) ; high byte 189 | push a ; pushing out of order 190 | ld a, (1, x) 191 | push a 192 | 193 | ld a, (6, y) ; polarity bit 194 | ldw x, y 195 | ldw x, (4, x) ; register with polarity 196 | xor a, (x) ; invert polarity 197 | ld (x), a 198 | 199 | popw x 200 | swapw x ; high byte was pushed first 201 | 202 | and a, (6, y) ; check new polarity 203 | jrne 00001$ ; rising edge, so record start count 204 | 205 | subw x, (1, sp) ; current - start = length 206 | 207 | ld a, _clock_hi 208 | sbc a, (9, y) ; check for excess time 209 | jreq 00003$ 210 | ldw x, #0xffff 211 | 00003$: 212 | pushw x 213 | ldw x, y 214 | ldw x, (x) ; output pin and callback 215 | ldw x, (2, x) ; callback 216 | call (x) 217 | popw x 218 | jra 00002$ 219 | 220 | 00001$: 221 | ldw (7, y), x 222 | ld a, _clock_hi 223 | ld (9, y), a 224 | 225 | 00002$: 226 | addw sp, #2 227 | __endasm; 228 | } 229 | 230 | /****************************************************************************** 231 | * 232 | * Timer2 capture interrupt 233 | */ 234 | 235 | void ping_isr_cap(void) __interrupt (IRQ_TIM2C) 236 | { 237 | __asm 238 | #ifdef PING_USE_C1 239 | btjf _active, #1, 00002$ 240 | btjf _TIM2_SR1, #1, 00002$ 241 | ldw x, #_ping_data 242 | call _isr_chan 243 | 00002$: 244 | #endif 245 | #ifdef PING_USE_C2 246 | btjf _active, #2, 00003$ 247 | btjf _TIM2_SR1, #2, 00003$ 248 | ldw x, #_ping_data+10 249 | call _isr_chan 250 | 00003$: 251 | #endif 252 | #ifdef PING_USE_C3 253 | btjf _active, #3, 00009$ 254 | btjf _TIM2_SR1, #3, 00009$ 255 | ldw x, #_ping_data+20 256 | call _isr_chan 257 | 00009$: 258 | #endif 259 | __endasm; 260 | } 261 | 262 | /****************************************************************************** 263 | * 264 | * Timer2 clock interrupt 265 | */ 266 | 267 | void ping_isr_clk(void) __interrupt (IRQ_TIM2C) 268 | { 269 | __asm 270 | bres _TIM2_SR1, #0 /* clear interrupt */ 271 | inc _clock_hi 272 | __endasm; 273 | } 274 | 275 | /****************************************************************************** 276 | * 277 | * Notes on the HC-SR04 module: 278 | * 279 | * The host starts a new ping by raising the "trigger" pin for 280 | * ten microseconds. The output ("echo") line is low for about 281 | * 450 microseconds, then goes high to give a pulse that is the 282 | * round trip time of the ultrasonic pulse. 283 | * 284 | * So we want to start our count at the "echo" positive edge, 285 | * and get the end count at the negative edge. Then it is just 286 | * dividing by the speed of sound to get centimeters or inches. 287 | * 288 | * It appears that if the unit does not receive an echo, the 289 | * output will stay high for about 190 milliseconds and ignore 290 | * a new trigger during this time. 291 | */ 292 | -------------------------------------------------------------------------------- /lib_ping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_ping.h 3 | * Date first: 11/04/2018 4 | * Date last: 12/04/2018 5 | * 6 | * Description: STM8 Library for HC-SR04 ultrasonic range finder. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * IMPORTANT: This library is not compatible with lib_pwm. 14 | * 15 | ****************************************************************************** 16 | * 17 | * Bring in IO pin structures 18 | */ 19 | #include "lib_pins.h" 20 | 21 | /* 22 | * LIBRARY CONFIGURATION: 23 | * 24 | * Save code space by enabling only the PING channels you use. 25 | * Comment out (or delete) the channels you do not use. 26 | */ 27 | #define PING_USE_C1 28 | #define PING_USE_C2 29 | #define PING_USE_C3 30 | 31 | /* 32 | * Initialize device 33 | * in: Timer2 channels, output pin(s), callback function(s) 34 | */ 35 | 36 | void ping_init(char, IO_CALL_INT *); 37 | 38 | /* Channels and their pins on STM8S103 20SSOP */ 39 | 40 | #define PING_CHAN1 1 /* D4 pin 1 */ 41 | #define PING_CHAN2 2 /* D3 pin 20 */ 42 | #define PING_CHAN3 4 /* A3 pin 10 */ 43 | 44 | /* Callback function gets round trip time in microseconds, or -1 (0xffff) 45 | * if there is no echo response. This callback is in interrupt context, 46 | * so don't make expensive function calls. Be alert for possible races. 47 | */ 48 | 49 | /* Divisors to convert return value into CM, inches, or microseconds */ 50 | 51 | #define PING_CM 58 /* get distance in centimeters */ 52 | #define PING_INCH 148 /* get distance in inches */ 53 | #define PING_USEC 2 /* get distance in microseconds */ 54 | 55 | /* 56 | * Start ping process (ping may take up to 20ms to complete) 57 | * in: Channel: PING_CHAN1/2/3 58 | */ 59 | 60 | void ping_send(char); 61 | 62 | void ping_isr_clk(void) __interrupt (IRQ_TIM2); 63 | void ping_isr_cap(void) __interrupt (IRQ_TIM2C); 64 | -------------------------------------------------------------------------------- /lib_pins.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_pins.h 3 | * Date first: 11/04/2018 4 | * Date last: 11/14/2018 5 | * 6 | * Description: STM8 Library to simplify pin usage. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Structured pin definition 16 | */ 17 | typedef struct { 18 | volatile char *reg_base; /* port ODR register */ 19 | char reg_mask; /* bit to use */ 20 | } IO_PIN; 21 | 22 | /* Define one pin and a callback function */ 23 | 24 | typedef struct { 25 | IO_PIN *pin; 26 | void (*callback)(void); 27 | } IO_CALL; 28 | 29 | /* Define one pin and a callback function that gets int */ 30 | 31 | typedef struct { 32 | IO_PIN *pin; 33 | void (*callback)(int); 34 | } IO_CALL_INT; 35 | -------------------------------------------------------------------------------- /lib_pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_pwm.c 3 | * Date first: 08/20/2018 4 | * Date last: 08/22/2018 5 | * 6 | * Description: STM8 Library for PWM and servos 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | 17 | #include "stm8s_header.h" 18 | 19 | #include "lib_eeprom.h" 20 | #include "lib_pwm.h" 21 | 22 | static void set_duty(char, unsigned int); /* internal set duty cycle */ 23 | static void set_remap(char); /* set remap channel 3 pin on STM8S105 */ 24 | 25 | /****************************************************************************** 26 | * 27 | * Initialize PWM 28 | * in: mode, channels to use 29 | */ 30 | 31 | void pwm_init(char mode, char chans) 32 | { 33 | #ifdef STM8103 34 | TIM2_PSCR = 3; /* prescaler = 8 for 16mhz */ 35 | #endif 36 | #ifdef STM8105 37 | char remap = 0; 38 | TIM2_PSCR = 2; /* prescaler = 4 for 8mhz */ 39 | #endif 40 | switch (mode) { 41 | case PWM_DUTY : 42 | TIM2_ARRH = 0; 43 | TIM2_ARRL = 199; /* 100 uS = 10khz */ 44 | break; 45 | case PWM_SERVO : 46 | TIM2_ARRH = 39999 >> 8; /* 20000 uS = 50 hz */ 47 | TIM2_ARRL = 39999 & 255; 48 | break; 49 | } 50 | if (chans & PWM_C1) { 51 | TIM2_CCR1H = 0; 52 | TIM2_CCR1L = 0; 53 | TIM2_CCMR1 = 0x68; /* PWM mode 1, use preload register */ 54 | TIM2_CCER1 |= 0x01; /* output enable, normal polarity */ 55 | } 56 | if (chans & PWM_C2) { 57 | TIM2_CCR2H = 0; 58 | TIM2_CCR2L = 0; 59 | TIM2_CCMR2 = 0x68; 60 | TIM2_CCER1 |= 0x10; 61 | } 62 | if (chans & PWM_C3) { 63 | #ifdef STM8105 64 | remap = 2; 65 | #endif 66 | TIM2_CCR3H = 0; 67 | TIM2_CCR3L = 0; 68 | TIM2_CCMR3 = 0x68; 69 | TIM2_CCER2 |= 0x01; 70 | } 71 | #ifdef STM8105 72 | set_remap(remap); 73 | #endif 74 | TIM2_CR1 = 0x81; /* use TIM2_ARR preload register, enable */ 75 | } 76 | 77 | /****************************************************************************** 78 | * 79 | * Set new PWM duty cycle 80 | * in: channel(s), percentage/2: 0 to 200 81 | */ 82 | 83 | void pwm_duty(char chan, char duty) 84 | { 85 | set_duty(chan, duty); 86 | } 87 | 88 | /****************************************************************************** 89 | * 90 | * Set new servo position 91 | * in: channel(s), position: 0 to 250 92 | */ 93 | 94 | void pwm_servo(char chan, char pos) 95 | { 96 | int duty; 97 | 98 | duty = pos * 16; /* get 0 to 2000 milliseconds */ 99 | duty += 1000; /* now 500 to 2500 mS */ 100 | 101 | set_duty(chan, duty); 102 | } 103 | 104 | /****************************************************************************** 105 | * 106 | * Set duty count 107 | * in: channel(s), new duty count (times 1/2 microsecond) 108 | */ 109 | 110 | static void set_duty(char chan, unsigned int duty) 111 | { 112 | char ch, cl; 113 | 114 | ch = duty >> 8; 115 | cl = duty & 0xff; 116 | 117 | if (chan & PWM_C1) { 118 | TIM2_CCR1H = ch; 119 | TIM2_CCR1L = cl; 120 | } 121 | if (chan & PWM_C2) { 122 | TIM2_CCR2H = ch; 123 | TIM2_CCR2L = cl; 124 | } 125 | if (chan & PWM_C3) { 126 | TIM2_CCR3H = ch; 127 | TIM2_CCR3L = cl; 128 | } 129 | } 130 | 131 | /****************************************************************************** 132 | * 133 | * Set remapping for output channel 3 on STM8S105K 134 | * in: 0 = no, 2 = yes 135 | */ 136 | #ifdef STM8105 137 | static void set_remap(char val) 138 | { 139 | char cfg; 140 | 141 | eeprom_unlock(); 142 | FLASH_CR2 = 0x80; /* enable option byte */ 143 | FLASH_NCR2 = 0x7f; 144 | cfg = OPT2; 145 | cfg &= 0xfd; 146 | cfg |= val; 147 | OPT2 = cfg; 148 | NOPT2 = ~cfg; 149 | eeprom_lock(); 150 | } 151 | #endif 152 | -------------------------------------------------------------------------------- /lib_pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_pwm.h 3 | * Date first: 08/20/2018 4 | * Date last: 08/22/2018 5 | * 6 | * Description: STM8 Library for PWM and servos 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * One, two, or three channels are supported. 16 | * This library uses Timer2 17 | * 18 | * STM8S103F: 19 | * C1 = pin 1 (D4) alt: 15 (C5) 20 | * C2 = pin 20 (D3) 21 | * C3 = pin 10 (A3) alt: 19 (D2) 22 | * 23 | * STM8S105K: (change pin numbers for SPDIP32) 24 | * C1 = pin 29 (D4) 25 | * C2 = pin 28 (D3) 26 | * C3 = pin 27 (D2) reassigned: note pin A3 is only on the 48 pin part 27 | * 28 | * Initialize PWM 29 | * in: mode, channels to use 30 | */ 31 | 32 | void pwm_init(char, char); 33 | 34 | #define PWM_DUTY 1 /* duty cycle 0 to 100 percent */ 35 | #define PWM_SERVO 2 /* send servo signal every 20ms */ 36 | 37 | #define PWM_C1 1 38 | #define PWM_C2 2 39 | #define PWM_C3 4 40 | 41 | /* 42 | * Set new PWM duty cycle 43 | * in: channel(s), percentage/2: 0 to 200 44 | */ 45 | 46 | void pwm_duty(char, char); 47 | 48 | /* 49 | * Set new servo position 50 | * in: channel(s), position: 0 to 255 (0.5 to 2.5 mS 125 is center: 1.5 mS) 51 | */ 52 | 53 | void pwm_servo(char, char); 54 | 55 | /* Stated specs: 56 | * Tower Pro SG90: 0.5 to 2.4 mS (https://servodatabase.com/servo/towerpro/sg90) 57 | * Futaba S3003: 0.5 to 3.0 mS (https://servodatabase.com/servo/futaba/s3003) 58 | * Note: Seems to stop before 2.5 mS 59 | */ 60 | -------------------------------------------------------------------------------- /lib_rotary.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_rotary.c 3 | * Date first: 12/29/2017 4 | * Date last: 06/24/2018 5 | * 6 | * Description: STM8 Library for ALPS rotary encoder 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Pinout: 16 | * 17 | * PA1: encoder A 18 | * PA2: encoder B 19 | */ 20 | 21 | #include "stm8s_header.h" 22 | #include "lib_rotary.h" 23 | 24 | #define PIN_MASK (2 | 4) 25 | 26 | static char val_cur; 27 | static char val_max; 28 | static char direction; 29 | static char pins_last; 30 | static char roll_up, roll_down; 31 | 32 | /****************************************************************************** 33 | * 34 | * Setup 35 | * in: number of steps 36 | */ 37 | 38 | void alps_init(char steps, char option) 39 | { 40 | PA_DDR &= ~(PIN_MASK); /* PA1, PA2 inputs */ 41 | PA_CR2 &= ~(PIN_MASK); /* no interrupts */ 42 | PA_CR1 |= (PIN_MASK); /* weak pullups */ 43 | 44 | val_cur = 0; 45 | val_max = steps; 46 | direction = 0; 47 | pins_last = PA_IDR & PIN_MASK; 48 | 49 | /* assume ALPS_LIMITS option */ 50 | roll_up = steps - 1; /* new value when val_cur hits maximum */ 51 | roll_down = 1; /* value (adjusted ) when val_cur goes < 0 */ 52 | if (option == ALPS_ROLLOVER) { 53 | roll_up = 0; 54 | roll_down = steps; 55 | } 56 | } 57 | 58 | /****************************************************************************** 59 | * 60 | * Get current position (relative from setup) 61 | */ 62 | 63 | char alps_value(void) 64 | { 65 | return val_cur; 66 | } 67 | 68 | /****************************************************************************** 69 | * 70 | * Poll switch (recommended: 1 to 4 milliseconds 71 | */ 72 | 73 | void alps_poll(void) 74 | { 75 | char pins_cur; 76 | char diff; 77 | 78 | pins_cur = PA_IDR & PIN_MASK; 79 | if ((pins_cur == 0) || /* are both pins zero? */ 80 | (pins_cur == PIN_MASK)) { /* both set? */ 81 | if (pins_cur == pins_last) 82 | return; 83 | pins_last = pins_cur; 84 | if (direction) { 85 | val_cur++; 86 | if (val_cur == val_max) 87 | val_cur = roll_up; 88 | return; 89 | } 90 | if (val_cur == 0) 91 | val_cur = roll_down; 92 | val_cur--; 93 | return; 94 | } 95 | diff = pins_cur ^ pins_last; 96 | direction = 0; /* counter-clockwise */ 97 | if (diff == 4) /* pin B changed */ 98 | direction = 1; /* clockwise */ 99 | } 100 | 101 | /****************************************************************************** 102 | 103 | The ALPS rotary encoder switch has 30 detent positions, each one spaced 12 104 | degrees apart. The three (encoder) pins are A (left), Common, B (right). 105 | Pins A and B should be pulled up to Vcc; 10K resistors are recommended to 106 | keep current under 1mA. Here, the input pins have internal pull-ups of 107 | about 40K. 108 | 109 | Both A and B are stable at detent position, and both A and B will have 110 | the same output. When the encoder is rotated clockwise, B will change 111 | first, then A. For counterclockwise, A will change first, then B. 112 | 113 | Instead of using Interrupt On Change, poll at a rate often enough to 114 | catch the fastest transitions. One full revolution in half a second 115 | might be a good starting point, which gives 60 pin changes per second, 116 | or one every 16 milliseconds. Oversampling by 4 would give one poll 117 | every 4 milliseconds, which is probably already a timer interrupt. 118 | 119 | 0. Read pins A and B, save starting status. 120 | 121 | Polling procedure: 122 | 123 | 1. Are pins A and B the same? 124 | NO: Which changed from saved status? Set direction flag. Exit. 125 | YES: Continue to 2. 126 | 127 | 2. Are A and B equal to last saved status? 128 | YES: Encoder at same detent position. Ignore. Exit. 129 | NO: Save new status. Eval direction flag and indicate rotation. 130 | */ 131 | -------------------------------------------------------------------------------- /lib_rotary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_rotary.h 3 | * Date first: 12/29/2017 4 | * Date last: 06/24/2018 5 | * 6 | * Description: STM8 Library for ALPS rotary encoder 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Setup 16 | * in: number of steps, LIMITS or ROLLOVER 17 | */ 18 | void alps_init(char steps, char option); 19 | 20 | #define ALPS_LIMITS 1 /* value stops at zero, maximum steps */ 21 | #define ALPS_ROLLOVER 2 /* below zero and over maximum rolls over */ 22 | 23 | /* 24 | * Get current position (relative from setup) 25 | */ 26 | char alps_value(void); 27 | 28 | /* 29 | * Poll switch (recommended: 1 to 4 milliseconds 30 | */ 31 | void alps_poll(void); 32 | -------------------------------------------------------------------------------- /lib_spi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_spi.c 3 | * Date first: 05/29/2020 4 | * Date last: 07/08/2020 5 | * 6 | * Description: STM8 Library for hardware SPI. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2020 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * Location: 14 | * https://github.com/unfrozen/stm8_libs 15 | * 16 | ****************************************************************************** 17 | * 18 | * Includes 19 | */ 20 | 21 | #include "stm8s_header.h" 22 | #include "lib_spi.h" 23 | 24 | /****************************************************************************** 25 | * 26 | * Current SPI context, data pointers, and counts 27 | */ 28 | 29 | static SPI_CTX *ctx_cur; 30 | 31 | static int tx_count; 32 | static int rx_count; 33 | static int tx_dummy; /* Dummy TX bytes needed for RX clock. */ 34 | 35 | static char *tx_buf; 36 | static char *rx_buf; 37 | 38 | static char rx_debug; /* Incrementing value to debug RX */ 39 | 40 | /****************************************************************************** 41 | * 42 | * Interrupt handlers 43 | */ 44 | 45 | static void irq_idle(void); 46 | static void irq_read(void); 47 | static void irq_write(void); 48 | static void irq_rw(void); 49 | 50 | static void (*irq_current)(void); 51 | 52 | /****************************************************************************** 53 | * 54 | * Initialize SPI 55 | * in: SPI context 56 | */ 57 | 58 | void spi_init(SPI_CTX *ctx) 59 | { 60 | PC_DDR |= 0x20; /* C5 is clock, C6 is output (MOSI) */ 61 | PC_CR1 |= 0x20; /* Push-pull output */ 62 | PC_CR2 |= 0x20; /* High speed (10mhz) */ 63 | 64 | /* We can't set C6 to output (yet) because bidirectional mode won't work. 65 | * So we can't set C6 to high speed, either. Measured rise and fall 66 | * times are around 50 nanoseconds on C6 and 25 on C5. 67 | */ 68 | spi_config(ctx); 69 | irq_current = irq_idle; 70 | ctx->state = SPI_IDLE; 71 | ctx_cur = ctx; 72 | } 73 | 74 | /****************************************************************************** 75 | * 76 | * Start SPI transaction 77 | * in: SPI context 78 | * out: status code 79 | */ 80 | 81 | char spi_start(SPI_CTX *ctx) 82 | { 83 | /* Wait for final SPI write to finish. This is important when 84 | * an SPI write-only is followed by SPI read + write transaction. 85 | */ 86 | spi_wait(); 87 | SPI_DR; /* If last transfer was TX only, discard RX value. */ 88 | 89 | /* check for different SPI config */ 90 | if (ctx_cur != ctx) 91 | spi_config(ctx); 92 | 93 | tx_count = ctx->tx_count; 94 | rx_count = ctx->rx_count; 95 | tx_buf = ctx->tx_buf; 96 | rx_buf = ctx->rx_buf; 97 | ctx->flag_done = 0; 98 | 99 | tx_dummy = rx_count - tx_count; /* Negative is okay, not used. */ 100 | 101 | if (tx_count && rx_count) { 102 | ctx->state = SPI_RW; 103 | irq_current = irq_rw; 104 | SPI_ICR = SPI_ICR_RXIE | SPI_ICR_TXIE; 105 | return SPI_OK; 106 | } 107 | if (tx_count) { 108 | ctx->state = SPI_WRITE; 109 | irq_current = irq_write; 110 | if (ctx->flag_bidir) 111 | SPI_CR2 |= SPI_CR2_BDOE; 112 | SPI_ICR = SPI_ICR_TXIE; 113 | return SPI_OK; 114 | } 115 | if (rx_count) { 116 | ctx->state = SPI_READ; 117 | irq_current = irq_read; 118 | SPI_ICR = SPI_ICR_RXIE; 119 | if (ctx->flag_bidir) { /* SPI clock starts when OE goes low */ 120 | SPI_CR2 &= ~SPI_CR2_BDOE; 121 | tx_dummy = 0; /* Don't send dummy TX bytes. */ 122 | } 123 | else { 124 | SPI_DR = rx_debug++; /* Start clock by writing TX. */ 125 | tx_dummy--; 126 | } 127 | SPI_ICR = SPI_ICR_RXIE; 128 | return SPI_OK; 129 | } 130 | return SPI_ERR; 131 | } 132 | 133 | /****************************************************************************** 134 | * 135 | * SPI interrupt handler 136 | */ 137 | 138 | void spi_isr(void) __interrupt (IRQ_SPI) __naked 139 | { 140 | // irq_current(); 141 | __asm 142 | ldw x, _irq_current 143 | call (x) 144 | iret 145 | __endasm; 146 | } 147 | 148 | /****************************************************************************** 149 | * 150 | * Idle interrupt handler 151 | */ 152 | 153 | static void irq_idle(void) 154 | { 155 | SPI_ICR = 0; /* done, so disable interrupts */ 156 | } 157 | 158 | /****************************************************************************** 159 | * 160 | * Reading interrupt handler 161 | */ 162 | 163 | static void irq_read(void) 164 | { 165 | char status; 166 | 167 | status = SPI_SR; 168 | if (status & SPI_SR_RXNE) { 169 | *rx_buf = SPI_DR; 170 | rx_buf++; 171 | rx_count--; 172 | } 173 | if ((status & SPI_SR_TXE) && 174 | tx_dummy) { /* Need to feed clock with TX byte? */ 175 | tx_dummy--; 176 | SPI_DR = rx_debug++; 177 | } 178 | if (rx_count) 179 | return; 180 | 181 | SPI_ICR = 0; 182 | irq_current = irq_idle; 183 | ctx_cur->state = SPI_IDLE; 184 | ctx_cur->flag_done = 1; 185 | 186 | /* Turn off the SPI clock. */ 187 | if (ctx_cur->flag_bidir) /* Go back to pin output mode. */ 188 | SPI_CR2 = SPI_CR2_BDM | SPI_CR2_BDOE; 189 | } 190 | 191 | /****************************************************************************** 192 | * 193 | * Writing interrupt handler 194 | */ 195 | 196 | static void irq_write(void) 197 | { 198 | if (tx_count) { 199 | SPI_DR = *tx_buf++; 200 | tx_count--; 201 | } 202 | if (tx_count) 203 | return; 204 | SPI_ICR = 0; 205 | irq_current = irq_idle; 206 | ctx_cur->state = SPI_IDLE; 207 | ctx_cur->flag_done = 1; /* Note that TX is still going now. */ 208 | } 209 | 210 | /****************************************************************************** 211 | * 212 | * Read and Write interrupt handler 213 | */ 214 | 215 | static void irq_rw(void) 216 | { 217 | char status; 218 | 219 | status = SPI_SR; 220 | 221 | if (status & SPI_SR_TXE) { 222 | SPI_DR = *tx_buf++; 223 | tx_count--; 224 | } 225 | if (status & SPI_SR_RXNE) { 226 | *rx_buf = SPI_DR; 227 | rx_buf++; 228 | rx_count--; 229 | } 230 | if (tx_count && rx_count) 231 | return; 232 | if (tx_count) { 233 | SPI_ICR = SPI_ICR_TXIE; 234 | irq_current = irq_write; 235 | ctx_cur->state = SPI_WRITE; 236 | return; 237 | } 238 | if (rx_count) { 239 | SPI_ICR = SPI_ICR_RXIE | SPI_ICR_TXIE; 240 | irq_current = irq_read; 241 | ctx_cur->state = SPI_READ; 242 | return; 243 | } 244 | SPI_ICR = 0; 245 | ctx_cur->state = SPI_IDLE; 246 | ctx_cur->flag_done = 1; 247 | } 248 | 249 | /****************************************************************************** 250 | * 251 | * Configure SPI 252 | * in: SPI context 253 | */ 254 | 255 | void spi_config(SPI_CTX *ctx) 256 | { 257 | SPI_CR1 = 0; /* Disable SPI. */ 258 | SPI_CR1 = ctx->config | 4; /* Load new config, choose master. */ 259 | 260 | /* If bidirectional (both TX and RX on same pin), we need to start 261 | * in TX mode (output enable); in RX mode, the SPI clock will start. */ 262 | if (ctx->flag_bidir) { 263 | PC_CR2 &= 0xbf; /* Can't use high speed mode. */ 264 | PC_DDR &= 0xbf; /* Because we can't set it to output only. */ 265 | SPI_CR2 = SPI_CR2_BDM | SPI_CR2_BDOE; 266 | } 267 | else { 268 | PC_DDR |= 0x40; /* Set MOSI pin to output mode. */ 269 | PC_CR2 |= 0x40; /* And to high speed. */ 270 | SPI_CR2 = 0; 271 | } 272 | SPI_CR1 |= SPI_CR1_SPE; /* enable SPI */ 273 | ctx_cur = ctx; 274 | } 275 | 276 | /****************************************************************************** 277 | * 278 | * Wait for previous SPI write to finish 279 | */ 280 | 281 | void spi_wait(void) 282 | { 283 | while (tx_count | rx_count); 284 | 285 | /* Check and wait for previous data to be sent. Refer to RM0016, 286 | * 20.3.7 (page 277) and 20.3.8 (page 278) for details. 287 | */ 288 | while (!(SPI_SR & SPI_SR_TXE)); /* wait for TXE=1 */ 289 | while (SPI_SR & SPI_SR_BSY); /* wait for BSY=0 */ 290 | } 291 | -------------------------------------------------------------------------------- /lib_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_spi.h 3 | * Date first: 05/29/2020 4 | * Date last: 07/08/2020 5 | * 6 | * Description: STM8 Library for hardware SPI. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2020 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * Location: 14 | * https://github.com/unfrozen/stm8_libs 15 | * 16 | ****************************************************************************** 17 | * 18 | * SPI context 19 | */ 20 | 21 | typedef struct { 22 | int tx_count; /* TX bytes to send */ 23 | int rx_count; /* RX bytes to get */ 24 | char *tx_buf; /* TX buffer, ignored if tx_count is zero */ 25 | char *rx_buf; /* RX buffer, ignored if rx_count is zero */ 26 | char config; /* see config values below */ 27 | char state; /* IDLE, READ, WRITE, or RW */ 28 | char flag_bidir; /* set if one pin (MOSI) is both RX & TX */ 29 | char flag_done; /* set when SPI transaction is almost done */ 30 | } SPI_CTX; 31 | 32 | /* 33 | * Note that flag_done is set when the read is complete, or the write buffer 34 | * is empty. When writing, the SPI will still be sending the last bits. 35 | * If you need to know that the SPI is inactive, use spi_wait() to be sure. 36 | */ 37 | 38 | /* 39 | * Initialize SPI 40 | */ 41 | void spi_init(SPI_CTX *); 42 | 43 | /* 44 | * Start SPI transaction 45 | * in: SPI context 46 | * out: status code 47 | * 48 | * NOTE: This function will wait (block) if there is current transaction. 49 | * NOTE: If bidirectional I/O, do not combine RX and TX in transaction. 50 | */ 51 | char spi_start(SPI_CTX *); 52 | 53 | /* 54 | * Wait for previous SPI transaction to finish. 55 | */ 56 | void spi_wait(void); 57 | 58 | /* 59 | * Reconfigure SPI for changed context. 60 | * 61 | * The spi_start() function will do this if needed, but if you have an 62 | * enable pin for the SPI device, you may need to change the configuration 63 | * before you assert the enable pin. A glitch in the SPI clock and/or MOSI 64 | * pin may upset the device. 65 | */ 66 | 67 | void spi_config(SPI_CTX *); 68 | 69 | /****************************************************************************** 70 | * 71 | * SPI status codes 72 | */ 73 | 74 | #define SPI_OK 0 75 | #define SPI_ERR 1 76 | #define SPI_DONE 2 77 | 78 | /****************************************************************************** 79 | * 80 | * SPI configuration values. 81 | * Logical OR them together 82 | */ 83 | 84 | /* SPI bit endian */ 85 | 86 | #define SPI_MSB_FIRST 0x00 87 | #define SPI_LSB_FIRST 0x80 88 | /* 89 | * SPI CLOCK SPEED 90 | */ 91 | #define SPI_8MHZ 0x00 92 | #define SPI_4MHZ 0x08 93 | #define SPI_2MHZ 0x10 94 | #define SPI_1MHZ 0x18 95 | #define SPI_500K 0x20 96 | #define SPI_250K 0x28 97 | #define SPI_125K 0x30 98 | #define SPI_62K 0x38 99 | 100 | /* SPI level when idle */ 101 | 102 | #define SPI_IDLE_0 0x00 /* Clock is low when idle. */ 103 | #define SPI_IDLE_1 0x02 /* Clock is high when idle. */ 104 | 105 | /* SPI "polarity", data on clock edge 1 or 2? */ 106 | 107 | #define SPI_EDGE_1 0x00 /* Data is valid on 1st clock edge from idle. */ 108 | #define SPI_EDGE_2 0x01 /* Data is valid on 2nd clock edge from idle. */ 109 | 110 | /* 111 | * SPI states 112 | */ 113 | #define SPI_IDLE 0 114 | #define SPI_READ 1 115 | #define SPI_WRITE 2 116 | #define SPI_RW 3 117 | 118 | /* 119 | * Interrupt service routine declaration 120 | */ 121 | void spi_isr(void) __interrupt (IRQ_SPI); 122 | 123 | -------------------------------------------------------------------------------- /lib_stm8.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unfrozen/stm8_libs/f7c6504d93273f73e07451468125a323e7da13e0/lib_stm8.lib -------------------------------------------------------------------------------- /lib_tim4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_tim4.c 3 | * Date first: 03/23/2018 4 | * Date last: 12/02/2018 5 | * 6 | * Description: Library for millisecond and 1/10 second callbacks using tim4. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018-2020 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * This is a stripped version of lib_clock. 14 | * 15 | ****************************************************************************** 16 | * 17 | */ 18 | 19 | #include "stm8s_header.h" 20 | 21 | #include "lib_tim4.h" 22 | 23 | static signed char clock_ms; /* milliseconds, may be negative with trim */ 24 | 25 | static void (*timer_ms)(void); 26 | static void (*timer_10)(void); 27 | 28 | /****************************************************************************** 29 | * 30 | * Initialize the clock (set up timer 4) 31 | * in: Millisecond callback, 1/10 second callback 32 | */ 33 | 34 | void tim4_init(void (*call_ms)(void), void (*call_10)(void)) 35 | { 36 | timer_ms = call_ms; 37 | timer_10 = call_10; 38 | 39 | #ifdef STM8103 40 | TIM4_PSCR = 6; /* prescaler = 64 for 16mhz */ 41 | #endif 42 | #ifdef STM8105 43 | TIM4_PSCR = 5; /* prescaler = 32 for 8mhz */ 44 | #endif 45 | #ifdef STM8S207 46 | TIM4_PSCR = 6; /* prescaler = 64 for 16mhz */ 47 | #endif 48 | TIM4_ARR = 249; /* reset and interrupt every 1.0 ms */ 49 | TIM4_CR1 = 1; /* enable timer4 */ 50 | TIM4_IER = 1; /* enable timer4 interrupt */ 51 | } 52 | 53 | /****************************************************************************** 54 | * 55 | * Timer 4 interrupt 56 | */ 57 | 58 | void tim4_isr(void) __interrupt (IRQ_TIM4) 59 | { 60 | TIM4_SR = 0; /* clear the interrupt */ 61 | 62 | timer_ms(); 63 | clock_ms++; 64 | if (clock_ms < 100) 65 | return; 66 | clock_ms -= 100; 67 | 68 | timer_10(); 69 | } 70 | -------------------------------------------------------------------------------- /lib_tim4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_tim4.h 3 | * Date first: 03/23/2018 4 | * Date last: 12/02/2020 5 | * 6 | * Description: Library for millisecond and 1/10 second callbacks using tim4. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018-2020 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * This is a stripped version of lib_clock. 14 | * 15 | ****************************************************************************** 16 | * 17 | * Initialize the clock (set up timer 4) 18 | * in: Millisecond callback, 1/10 second callback 19 | */ 20 | 21 | void tim4_init(void (*)(void), void (*)(void)); 22 | 23 | void tim4_isr(void) __interrupt (IRQ_TIM4); 24 | 25 | -------------------------------------------------------------------------------- /lib_tm1637.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_tm1637.c 3 | * Date first: 06/08/2018 4 | * Date last: 06/13/2019 5 | * 6 | * Description: STM8 Library for TM1637 4 digit LED array. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * Base code copied from lib_tm1638.c 14 | * 15 | ****************************************************************************** 16 | * 17 | */ 18 | 19 | #include "stm8s_header.h" 20 | #include "lib_i2c.h" 21 | #include "lib_tm1637.h" 22 | 23 | /* Note that the I2C pins are defined in lib_i2c.c 24 | * Clock = D2, Data = D3 25 | */ 26 | 27 | #define COLON_POS 1 /* LED that has colon in bit-7 */ 28 | 29 | #define SEG_INVALID 0x49 /* "invalid", three horizontal bars */ 30 | 31 | static char led_col; /* digit 7-seg always 0-3 */ 32 | static char led_bright; /* normal brightness */ 33 | 34 | static char blink_rate; /* blink rate, time 1/100 second */ 35 | static char blink_count; 36 | static char blink_ms; 37 | static char blink_flags; 38 | 39 | static char colon_bars; /* bars for LED with colon bit */ 40 | 41 | static void emit_byte(char); /* send byte */ 42 | static void emit_segs(char, char); /* send 7-segment to LED */ 43 | 44 | static char code_7seg(char); /* get 7-segment code for ASCII character */ 45 | 46 | const char segs_1637_digits[]; 47 | const char segs_1637_alpha[]; 48 | 49 | static volatile char lock; 50 | 51 | /****************************************************************************** 52 | * 53 | * Initialize device 54 | */ 55 | 56 | void tm1637_init(void) 57 | { 58 | led_col = 0; 59 | 60 | i2c_init(); 61 | 62 | tm1637_bright(5); /* active and brightness */ 63 | tm1637_clear(); 64 | 65 | lock = 0; 66 | blink_rate = 0; 67 | } 68 | 69 | /****************************************************************************** 70 | * 71 | * Set cursor position 72 | * in: line or unit# (0-max), column 73 | */ 74 | 75 | void tm1637_curs(char col) 76 | { 77 | led_col = col; 78 | } 79 | 80 | /****************************************************************************** 81 | * 82 | * Write number/string to unit 83 | * in: number/string 84 | */ 85 | 86 | void tm1637_puts(char *str) 87 | { 88 | char c; 89 | while (c = *str++) 90 | tm1637_putc(c); 91 | } 92 | 93 | /****************************************************************************** 94 | * 95 | * Get 7-segment code for ASCII character 96 | */ 97 | 98 | static char code_7seg(char c) 99 | { 100 | if (c == ' ') 101 | return 0; 102 | if (c == '-') 103 | return 0x40; 104 | if (c == '_') 105 | return 8; 106 | if ((c & 0xf0) == 0x30) 107 | return segs_1637_digits[c & 0x0f]; 108 | if (c < 'A' || 109 | c > 'U') 110 | return SEG_INVALID; 111 | return segs_1637_alpha[c - 'A']; 112 | } 113 | 114 | /****************************************************************************** 115 | * 116 | * Write 7-segment bars to LED 117 | * in: position, segments 118 | */ 119 | 120 | static void emit_segs(char pos, char segs) 121 | { 122 | lock = 1; 123 | 124 | i2c_start(); 125 | emit_byte(0x44); /* data write, no increment */ 126 | i2c_getack(); 127 | i2c_stop(); 128 | 129 | i2c_start(); 130 | emit_byte(0xc0 | pos); 131 | i2c_getack(); 132 | emit_byte(segs); 133 | i2c_getack(); 134 | i2c_stop(); 135 | 136 | lock = 0; 137 | } 138 | 139 | /****************************************************************************** 140 | * 141 | * Write digit/char to unit 142 | * in: digit or char 143 | */ 144 | 145 | void tm1637_putc(char c) 146 | { 147 | char pos, segs; 148 | 149 | pos = led_col; 150 | if (c == ':') { 151 | segs = colon_bars | 0x80; 152 | colon_bars = segs; 153 | emit_segs(COLON_POS, segs);/* re-write LED with colon */ 154 | return; 155 | } 156 | pos = led_col; 157 | segs = code_7seg(c & 0x7f); 158 | if (pos == COLON_POS) 159 | colon_bars = segs; 160 | emit_segs(pos, segs); 161 | 162 | led_col++; 163 | led_col &= 3; 164 | } 165 | 166 | /****************************************************************************** 167 | * 168 | * Clear all displays 169 | */ 170 | 171 | void tm1637_clear(void) 172 | { 173 | tm1637_curs(0); 174 | do 175 | tm1637_putc(' '); 176 | while (led_col); 177 | } 178 | 179 | /****************************************************************************** 180 | * 181 | * Set LED intensity (and clear test mode) 182 | * in: 0 (minimum) to 7 (maximum) 183 | */ 184 | 185 | void tm1637_bright(char intensity) 186 | { 187 | lock = 1; 188 | 189 | led_bright = intensity; 190 | i2c_start(); 191 | emit_byte(0x88 | intensity); 192 | i2c_getack(); 193 | i2c_stop(); 194 | 195 | lock = 0; 196 | } 197 | 198 | /****************************************************************************** 199 | * 200 | * Set the display colon 201 | * in: 0 (off) not zero (on) 202 | */ 203 | void tm1637_colon(char on) 204 | { 205 | char new; 206 | 207 | new = colon_bars & 0x7f; 208 | if (on) 209 | new |= 0x80; 210 | emit_segs(COLON_POS, new); 211 | colon_bars = new; 212 | } 213 | 214 | /****************************************************************************** 215 | * 216 | * Set LED blinking 217 | * Alternates between regular and minimum brightness. 218 | * in: Blink rate * 1/100 second or 0 (disable) 219 | */ 220 | void tm1637_blink(char rate) 221 | { 222 | blink_rate = rate; 223 | blink_count = rate; 224 | blink_flags = 0x80; 225 | blink_ms = 10; 226 | if (rate) 227 | return; 228 | tm1637_bright(led_bright); /* blink off, back to normal */ 229 | } 230 | 231 | /****************************************************************************** 232 | * 233 | * Poll for blink event 234 | * (Call every millisecond) 235 | */ 236 | 237 | static void blink_check(void) 238 | { 239 | char command; 240 | 241 | if (!blink_rate) 242 | return; 243 | if ((blink_flags & 0x80) && /* pending brightness change? */ 244 | !lock) { /* and okay to write? */ 245 | blink_flags ^= 0x80; 246 | command = 0x80; /* display off */ 247 | if (blink_flags & 1) 248 | command |= 0x08 | led_bright; 249 | i2c_start(); 250 | emit_byte(command); 251 | i2c_getack(); 252 | i2c_stop(); 253 | } 254 | blink_ms--; 255 | if (blink_ms) 256 | return; 257 | blink_ms = 10; 258 | blink_count--; 259 | if (blink_count) 260 | return; 261 | blink_count = blink_rate; 262 | blink_flags |= 0x80; /* brightness change pending */ 263 | blink_flags ^= 0x01; /* normal or minimum brightness */ 264 | } 265 | 266 | /****************************************************************************** 267 | * 268 | * aaa 000 269 | * f b 5 1 270 | * f b 5 1 271 | * ggg 666 272 | * e c 4 2 273 | * e c 4 2 274 | * ddd h 333 7 275 | */ 276 | 277 | const char segs_1637_digits[16] = { 278 | 0x3f, 0x06, 0x5b, 0x4f, 0x66, /* 0 - 4 */ 279 | 0x6d, 0x7d, 0x07, 0x7f, 0x67, /* 5 - 9 */ 280 | SEG_INVALID, SEG_INVALID, SEG_INVALID, 0x48, SEG_INVALID, SEG_INVALID 281 | }; 282 | const char segs_1637_alpha[21] = { 283 | 0x77, /* A */ 284 | 0x7c, /* B */ 285 | 0x39, /* C */ 286 | 0x5e, /* D */ 287 | 0x79, /* E */ 288 | 0x71, /* F */ 289 | SEG_INVALID, /* G */ 290 | 0x76, /* H */ 291 | 0x06, /* I shared with 1 */ 292 | 0x0e, /* J */ 293 | SEG_INVALID, /* K */ 294 | 0x38, /* L */ 295 | SEG_INVALID, /* M */ 296 | 0x54, /* N (small n) */ 297 | 0x5c, /* O (small o) */ 298 | 0x73, /* P */ 299 | SEG_INVALID, /* Q */ 300 | 0x50, /* R (small r) */ 301 | 0x6d, /* S shared with 5 */ 302 | 0x78, /* T (small t) */ 303 | 0x3e /* U */ 304 | }; 305 | 306 | /****************************************************************************** 307 | * 308 | * Poll for blinking 309 | * (every millisecond) 310 | */ 311 | void tm1637_poll(void) 312 | { 313 | blink_check(); 314 | } 315 | 316 | /****************************************************************************** 317 | * 318 | * Transmit 8 bits 319 | */ 320 | 321 | void emit_byte(char bits) 322 | { 323 | bits; 324 | __asm 325 | push #8 326 | 00001$: 327 | #if __SDCCCALL == 0 328 | srl (4, sp) 329 | #else 330 | srl a 331 | #endif 332 | jrnc 00010$ 333 | call _i2c_data1 334 | call _i2c_data1 335 | call _i2c_data1 336 | jra 00020$ 337 | 00010$: 338 | call _i2c_data0 339 | 00020$: 340 | call _i2c_clock1 341 | call _i2c_clock1 342 | call _i2c_clock0 343 | 344 | dec (1, sp) 345 | jrne 00001$ 346 | 347 | add sp, #1 348 | __endasm; 349 | } 350 | -------------------------------------------------------------------------------- /lib_tm1637.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_tm1638.h 3 | * Date first: 06/08/2018 4 | * Date last: 06/30/2018 5 | * 6 | * Description: STM8 Library for TM1638 LED array and keys. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * Some code copied from lib_max7219.h 13 | * 14 | ****************************************************************************** 15 | * 16 | * Initialize LED array 17 | */ 18 | 19 | void tm1637_init(); 20 | 21 | /* The cheap 4 digit display has a colon between the first 2 and last 2 digits. 22 | * If your string has a colon after the first 2 digits, the colon will display. 23 | * Otherwise, the colon will be blank. You can also turn the colon on and off 24 | * with the tm1637_colon() function below. 25 | */ 26 | 27 | /* 28 | * Write digit/char to unit 29 | * in: digit/char (ASCII). 30 | */ 31 | 32 | void tm1637_putc(char); 33 | 34 | /* 35 | * Write number/ASCII string to unit 36 | * in: string (insert decimal point where desired.) 37 | */ 38 | 39 | void tm1637_puts(char *); 40 | 41 | /* 42 | * Set cursor position 43 | * in: column (0-3) 44 | */ 45 | 46 | void tm1637_curs(char); 47 | 48 | /* 49 | * Clear display 50 | */ 51 | 52 | void tm1637_clear(void); 53 | 54 | /* 55 | * Set the display colon 56 | * in: 0 (off) not zero (on) 57 | */ 58 | void tm1637_colon(char); 59 | 60 | /* 61 | * Set LED intensity 62 | * in: 0 (minimum) to 7 (maximum) 63 | */ 64 | void tm1637_bright(char); 65 | 66 | /* 67 | * Set LED blinking 68 | * Alternates between regular and minimum brightness. 69 | * in: Blink rate * 1/100 second or 0 (disable) 70 | */ 71 | void tm1637_blink(char); 72 | 73 | /* 74 | * Poll for blinking 75 | * (call every millisecond) 76 | */ 77 | void tm1637_poll(void); 78 | -------------------------------------------------------------------------------- /lib_tm1638.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_tm1638.h 3 | * Date first: 06/08/2018 4 | * Date last: 06/23/2018 5 | * 6 | * Description: STM8 Library for TM1638 LED array and keys. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * Some code copied from lib_max7219.h 13 | * 14 | ****************************************************************************** 15 | * 16 | * Initialize array 17 | * in: type 18 | */ 19 | 20 | void tm1638_init(char); 21 | 22 | #define TM1638_8 1 /* display with 8 keys and 8 LEDs */ 23 | #define TM1638_16 2 /* display with 16 keys, no LEDs */ 24 | 25 | /* NOTE: Support for the 16 key board is a compile time option */ 26 | #define TM1638_16_KEYS /* comment out if you don't need 16 key support */ 27 | 28 | /* 29 | * Write digit/char to unit 30 | * in: digit/char (ASCII). Bit-7 is decimal point 31 | */ 32 | 33 | void tm1638_putc(char); 34 | 35 | /* 36 | * Write number/ASCII string to unit 37 | * in: string (insert decimal point where desired.) 38 | */ 39 | 40 | void tm1638_puts(char *); 41 | 42 | /* 43 | * Push display changes to the LEDs (16 key board only). 44 | * LEDs are not updated until this call. 45 | */ 46 | void tm1638_push(void); 47 | 48 | /* 49 | * Set cursor position 50 | * in: column (0-7) 51 | */ 52 | 53 | void tm1638_curs(char); 54 | 55 | /* 56 | * Clear displays 57 | */ 58 | 59 | void tm1638_clear(void); 60 | 61 | /* 62 | * Set LED status (8 key board only) 63 | * in: LED number (0 to 7), new status (0=off, 1=red) 64 | */ 65 | void tm1638_setled(char, char); 66 | 67 | /* 68 | * Set LED intensity 69 | * in: 0 (minimum) to 7 (maximum) 70 | */ 71 | void tm1638_bright(char); 72 | 73 | /* 74 | * Set LED blinking 75 | * Alternates between regular and minimum brightness. 76 | * in: Blink rate * 1/100 second or 0 (disable) 77 | */ 78 | void tm1638_blink(char); 79 | 80 | /* 81 | * Poll for key press and blinking 82 | * (call every millisecond) 83 | */ 84 | void tm1638_poll(void); 85 | 86 | /* 87 | * Get key 88 | * out: key char ("0123456789ABCDEF"), zero if none 89 | * Bit-7 is low for key press, high for release. 90 | */ 91 | char tm1638_getc(void); 92 | 93 | /* Set alternate key mappings 94 | * in: key map has 8 or 16 characters for keys 95 | */ 96 | void tm1638_kmap(char *); 97 | 98 | -------------------------------------------------------------------------------- /lib_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_uart.c 3 | * Date first: 12/30/2017 4 | * Date last: 12/13/2022 5 | * 6 | * Description: STM8 Library for UART1 and UART2 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | */ 16 | #include "stm8s_header.h" 17 | 18 | #include "lib_uart.h" 19 | 20 | /* 21 | * Buffers and counters 22 | */ 23 | 24 | static char uart_rxbuf[UART_BUF_RX]; 25 | static char uart_txbuf[UART_BUF_TX]; 26 | 27 | static volatile char tx_get, tx_put; 28 | static volatile char rx_get, rx_put; 29 | 30 | static short rx_overruns; 31 | static short buf_overruns; 32 | 33 | /****************************************************************************** 34 | * 35 | * UART init 36 | * in: baud rate 37 | */ 38 | void uart_init(unsigned short baud) 39 | { 40 | rx_get = 0; 41 | rx_put = 0; 42 | tx_get = 0; 43 | tx_put = 0; 44 | rx_overruns = 0; 45 | buf_overruns = 0; 46 | 47 | PD_DDR |= 0x20; /* D5 is TX */ 48 | PD_DDR &= 0xbf; /* D6 is RX */ 49 | 50 | UART_BRR2 = baud & 0xff; /* write BRR2 first */ 51 | UART_BRR1 = baud >> 8; 52 | UART_CR1 = 0; /* 8 bits, no parity */ 53 | UART_CR2 = 0x2c; /* enable RX, TX, RX interrupts only */ 54 | UART_CR3 = 0; /* one stop bit, no synchronous */ 55 | UART_CR4 = 0; /* not using LIN */ 56 | UART_CR5 = 0; /* no smartcard, no IRDA */ 57 | } 58 | 59 | /****************************************************************************** 60 | * 61 | * Get number of bytes waiting in RX buf 62 | */ 63 | 64 | char uart_rsize(void) 65 | { 66 | signed char size; 67 | 68 | size = rx_put - rx_get; 69 | if (size < 0) 70 | size += UART_BUF_RX; 71 | return size; 72 | } 73 | 74 | /****************************************************************************** 75 | * 76 | * Get next received byte (wait for it) 77 | */ 78 | char uart_get(void) 79 | { 80 | char byte; 81 | 82 | while (rx_get == rx_put); 83 | 84 | byte = uart_rxbuf[rx_get]; 85 | rx_get++; 86 | rx_get &= (UART_BUF_RX - 1); 87 | 88 | return byte; 89 | } 90 | 91 | /****************************************************************************** 92 | * 93 | * Send byte 94 | */ 95 | void uart_put(char byte) 96 | { 97 | char new_ptr; 98 | 99 | new_ptr = (tx_put + 1) & (UART_BUF_TX - 1); 100 | while (tx_get == new_ptr); 101 | uart_txbuf[tx_put] = byte; 102 | tx_put = new_ptr; 103 | UART_CR2 |= SR_TXE; 104 | } 105 | 106 | /****************************************************************************** 107 | * 108 | * Send string 109 | * in: character string, terminated with binary 00 110 | */ 111 | void uart_puts(const char *str) 112 | { 113 | while (*str) 114 | uart_put(*str++); 115 | } 116 | 117 | /****************************************************************************** 118 | * 119 | * Send CR/LF 120 | */ 121 | void uart_crlf(void) 122 | { 123 | uart_put(0x0d); 124 | uart_put(0x0a); 125 | } 126 | 127 | /****************************************************************************** 128 | * 129 | * Get hardware and buffer RX overruns 130 | */ 131 | short uart_over_hw(void) 132 | { 133 | return rx_overruns; 134 | } 135 | short uart_over_buf(void) 136 | { 137 | return buf_overruns; 138 | } 139 | 140 | /****************************************************************************** 141 | * 142 | * TX interrupt 143 | */ 144 | void uart_tx_isr(void) __interrupt (IRQ_UART_TX) 145 | { 146 | if (tx_get == tx_put) { /* empty buffer? */ 147 | UART_CR2 &= ~SR_TXE; 148 | return; 149 | } 150 | UART_DR = uart_txbuf[tx_get]; 151 | tx_get = (tx_get + 1) & (UART_BUF_TX - 1); 152 | if (tx_get == tx_put) 153 | UART_CR2 &= ~SR_TXE; 154 | } 155 | 156 | /****************************************************************************** 157 | * 158 | * RX interrupt 159 | */ 160 | void uart_rx_isr(void) __interrupt (IRQ_UART_RX) 161 | { 162 | char rxbyte, new_ptr; 163 | 164 | if (UART_SR & SR_OR) 165 | rx_overruns++; 166 | rxbyte = UART_DR; 167 | uart_rxbuf[rx_put] = rxbyte; 168 | 169 | new_ptr = (rx_put + 1) & (UART_BUF_RX - 1); 170 | if (new_ptr != rx_get) 171 | rx_put = new_ptr; 172 | else 173 | buf_overruns++; 174 | } 175 | -------------------------------------------------------------------------------- /lib_uart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_uart.h 3 | * Date first: 12/30/2017 4 | * Date last: 12/13/2022 5 | * 6 | * Description: STM8 Library for UART1 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2017, 2018 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Set RX and TX buffer sizes here 16 | */ 17 | 18 | #define UART_BUF_RX 16 /* must be power of 2 */ 19 | #define UART_BUF_TX 16 /* must be power of 2 */ 20 | 21 | /* 22 | * UART init 23 | * in: baud rate (see defines below) 24 | */ 25 | void uart_init(unsigned short); 26 | 27 | /* 28 | * Get number of bytes waiting in RX buf 29 | */ 30 | char uart_rsize(void); 31 | 32 | /* 33 | * Get next received byte (wait for it) 34 | */ 35 | char uart_get(void); 36 | 37 | /* 38 | * Send byte 39 | */ 40 | void uart_put(char); 41 | 42 | /* 43 | * Send string (ending with binary 00) 44 | */ 45 | void uart_puts(const char *); 46 | 47 | /* 48 | * Send CR/LF (0x0d 0x0a) 49 | */ 50 | void uart_crlf(void); 51 | 52 | /* 53 | * Get hardware and buffer RX overruns 54 | */ 55 | short uart_over_hw(void); 56 | short uart_over_buf(void); 57 | 58 | /* 59 | * Interrupt prototypes must be included with main() 60 | */ 61 | 62 | #include "vectors.h" 63 | 64 | #ifdef STM8103 /* clock is 16mhz */ 65 | 66 | #define BAUD_1200 (0x4135) 67 | #define BAUD_2400 (0xa01b) 68 | #define BAUD_4800 (0xd005) 69 | #define BAUD_9600 (0x6803) 70 | #define BAUD_19200 (0x3401) 71 | #define BAUD_38400 (0x1a01) 72 | #define BAUD_57600 (0x1106) 73 | #define BAUD_115200 (0x080b) 74 | 75 | void uart_tx_isr(void) __interrupt (IRQ_UART_TX); 76 | void uart_rx_isr(void) __interrupt (IRQ_UART_RX); 77 | 78 | #define UART_SR UART1_SR 79 | #define UART_DR UART1_DR 80 | #define UART_BRR1 UART1_BRR1 81 | #define UART_BRR2 UART1_BRR2 82 | #define UART_CR1 UART1_CR1 83 | #define UART_CR2 UART1_CR2 84 | #define UART_CR3 UART1_CR3 85 | #define UART_CR4 UART1_CR4 86 | #define UART_CR5 UART1_CR5 87 | 88 | #endif /* STM8103 */ 89 | 90 | #ifdef STM8105 /* clock is 8mhz crystal */ 91 | 92 | #define BAUD_1200 (0xa01b) 93 | #define BAUD_2400 (0xd005) 94 | #define BAUD_4800 (0x6803) 95 | #define BAUD_9600 (0x3401) 96 | #define BAUD_19200 (0x1a01) 97 | #define BAUD_38400 (0x0d00) 98 | #define BAUD_57600 (0x080b) 99 | #define BAUD_115200 (0x0405) 100 | 101 | void uart_tx_isr(void) __interrupt (IRQ_UART2_TX); 102 | void uart_rx_isr(void) __interrupt (IRQ_UART2_RX); 103 | 104 | #define UART_SR UART2_SR 105 | #define UART_DR UART2_DR 106 | #define UART_BRR1 UART2_BRR1 107 | #define UART_BRR2 UART2_BRR2 108 | #define UART_CR1 UART2_CR1 109 | #define UART_CR2 UART2_CR2 110 | #define UART_CR3 UART2_CR3 111 | #define UART_CR4 UART2_CR4 112 | #define UART_CR5 UART2_CR5 113 | 114 | #endif /* STM8105 */ 115 | -------------------------------------------------------------------------------- /lib_w1209.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_w1209.c 3 | * Date first: 01/22/2019 4 | * Date last: 06/13/2019 5 | * 6 | * Description: STM8 Library for W1209 thermostat board. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2019 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | * Some common code borrowed from lib_tm1638.c 14 | * 15 | ****************************************************************************** 16 | * 17 | */ 18 | 19 | #include "stm8s_header.h" 20 | 21 | #include "lib_adc.h" 22 | #include "lib_w1209.h" 23 | 24 | static char key_buf[KB_SIZE]; 25 | static char key_db[3]; /* current debounce counts */ 26 | static volatile char key_get; 27 | static volatile char key_put; 28 | 29 | static char display[3]; 30 | static char cursor; 31 | static char led_cur; 32 | static char led_update; 33 | 34 | static char blink_rate; 35 | static char blink_count; 36 | static char blink_flag; 37 | static char blink_ms; 38 | 39 | #define SEG_INVALID 0x49 /* "invalid", three horizontal bars */ 40 | 41 | const char segs_w12_digits[]; 42 | const char segs_w12_alpha[]; 43 | 44 | static void poll_blink(); 45 | static void poll_keys(); 46 | static void poll_leds(); 47 | 48 | static char code_7seg(char); 49 | 50 | /****************************************************************************** 51 | * 52 | * Initialize board 53 | */ 54 | 55 | void w12_init(void) 56 | { 57 | CLK_CKDIVR = 0x00; /* internal clock 16mhz */ 58 | 59 | key_get = 0; 60 | key_put = 0; 61 | 62 | cursor = 0; 63 | led_cur = 2; 64 | led_update = LED_UPDATE; 65 | 66 | PA_DDR = 0x0e; /* A1-A3 outputs */ 67 | PA_CR1 = 0xff; /* inputs have pullup, outputs not open drain */ 68 | PA_CR2 = 0x00; /* no interrupts on inputs, 2mhz outputs */ 69 | 70 | PB_DDR = 0x30; /* B4-B5 outputs */ 71 | PB_CR1 = 0xff; /* optional because B4, B5 are open drain */ 72 | PB_CR2 = 0x00; 73 | 74 | PC_DDR = 0xc0; /* C3-C5 inputs, C6-C7 outputs */ 75 | PC_CR1 = 0xff; 76 | PC_CR2 = 0x00; 77 | 78 | PD_DDR = 0x3e; /* D6 input, D1-D5 outputs */ 79 | PD_CR1 = 0xff; 80 | PD_CR2 = 0x00; 81 | 82 | adc_init(ADC_CH6); /* D6, pin #3 */ 83 | 84 | __asm__ ("rim"); 85 | } 86 | 87 | /****************************************************************************** 88 | * 89 | * Write digit/char to LED 90 | * in: ASCII digit or char (use bit-7 for decimal point) 91 | */ 92 | 93 | void w12_putc(char c) 94 | { 95 | char segs; 96 | 97 | segs = code_7seg(c & 0x7f); 98 | segs |= (c & 0x80); 99 | display[cursor] = segs; 100 | cursor++; 101 | if (cursor == 3) 102 | cursor = 0; 103 | } 104 | 105 | /****************************************************************************** 106 | * 107 | * Write string to LED 108 | * in: ASCII string (insert decimal point where desired.) 109 | */ 110 | 111 | void w12_puts(char *str) 112 | { 113 | char c; 114 | while (c = *str++) { 115 | if (*str == '.') { 116 | c |= 0x80; 117 | str++; 118 | } 119 | w12_putc(c); 120 | } 121 | } 122 | 123 | /****************************************************************************** 124 | * 125 | * Set cursor position 126 | * in: column (0-2) 127 | */ 128 | 129 | void w12_curs(char curs) 130 | { 131 | cursor = curs; 132 | } 133 | 134 | /****************************************************************************** 135 | * 136 | * Set LED blinking 137 | * in: Blink rate * 1/100 second or 0 (disable) 138 | */ 139 | void w12_blink(char rate) 140 | { 141 | blink_rate = rate; 142 | blink_count = rate; 143 | blink_ms = 10; 144 | if (rate) 145 | return; 146 | blink_flag = 0; /* blink off, back to normal */ 147 | } 148 | 149 | /****************************************************************************** 150 | * 151 | * Get keypress 152 | * out: zero or ASCII key ('0' to '2'), bit-7 set if released 153 | */ 154 | 155 | char w12_getc(void) 156 | { 157 | char key; 158 | 159 | if (key_get == key_put) 160 | return 0; 161 | key = key_buf[key_get]; 162 | key_get++; 163 | if (key_get == KB_SIZE) 164 | key_get = 0; 165 | return key; 166 | } 167 | 168 | /****************************************************************************** 169 | * 170 | * Poll for display, keys, and blinking 171 | * (call every millisecond) 172 | */ 173 | void w12_poll(void) 174 | { 175 | led_update--; 176 | if (!led_update) { 177 | led_update = LED_UPDATE; 178 | poll_leds(); 179 | } 180 | poll_keys(); 181 | poll_blink(); 182 | } 183 | 184 | /****************************************************************************** 185 | * 186 | * Turn the relay and LED on/off 187 | * in: zero = off, non-zero = on 188 | */ 189 | 190 | void w12_relay(char on) 191 | { 192 | on; 193 | __asm 194 | ld a, (3, sp) 195 | sub a, #1 ; carry if zero 196 | ccf ; carry if non-zero 197 | bccm _PA_ODR, #3 198 | __endasm; 199 | } 200 | 201 | /****************************************************************************** 202 | * 203 | * Get the current temperature probe value 204 | * out: current A/D value, -1 if timeout 205 | */ 206 | 207 | short w12_probe(void) 208 | { 209 | return adc_avg(6); 210 | } 211 | 212 | /****************************************************************************** 213 | * 214 | * Poll for blink event 215 | * (Call every millisecond) 216 | */ 217 | 218 | static void poll_blink(void) 219 | { 220 | if (!blink_rate) 221 | return; 222 | blink_ms--; 223 | if (blink_ms) 224 | return; 225 | blink_ms = 10; 226 | blink_count--; 227 | if (blink_count) 228 | return; 229 | blink_count = blink_rate; 230 | blink_flag ^= 1; /* toggle LEDs */ 231 | } 232 | 233 | /****************************************************************************** 234 | * 235 | * Add key into buffer 236 | */ 237 | 238 | static void key_add(char key) 239 | { 240 | char put, *ptr; 241 | 242 | put = key_put; 243 | ptr = key_buf + put; 244 | put++; 245 | if (put == KB_SIZE) 246 | put = 0; 247 | if (put == key_get) /* buffer full? */ 248 | return; 249 | *ptr = key; 250 | key_put = put; 251 | } 252 | 253 | /****************************************************************************** 254 | * 255 | * Poll for keypress 256 | * (Call every millisecond) 257 | */ 258 | 259 | static void poll_keys(void) 260 | { 261 | char i, *db; 262 | char key_status; 263 | 264 | key_status = PC_IDR >> 3; /* keys are C3, C4, C5 */ 265 | key_status ^= 0xff; /* active low */ 266 | 267 | db = key_db; 268 | for (i = 0; i < 3; i++) { 269 | if (*db) { 270 | (*db)--; 271 | if (*db == 0) /* key released */ 272 | key_add(i + '0' + 0x80); 273 | } 274 | if (key_status & 1) { 275 | if (*db == 0) 276 | key_add(i + '0'); 277 | *db = KB_DEBOUNCE; 278 | } 279 | db++; 280 | key_status >>= 1; 281 | } 282 | 283 | } 284 | 285 | /****************************************************************************** 286 | * 287 | * Poll for LED display 288 | * (Call every millisecond) 289 | */ 290 | 291 | static void poll_leds(void) 292 | { 293 | __asm 294 | bset _PD_ODR, #4 ; LED #1 295 | bset _PB_ODR, #5 ; LED #2 296 | bset _PB_ODR, #4 ; LED #3 297 | 298 | tnz _blink_flag 299 | jrne 00090$ 300 | 301 | ld a, _led_cur 302 | clrw x 303 | ld xl, a 304 | ld a, (_display, x) 305 | 306 | rrc a 307 | bccm _PD_ODR, #5 ; A 308 | rrc a 309 | bccm _PA_ODR, #2 ; B 310 | rrc a 311 | bccm _PC_ODR, #7 ; C 312 | rrc a 313 | bccm _PD_ODR, #3 ; D 314 | rrc a 315 | bccm _PD_ODR, #1 ; E 316 | rrc a 317 | bccm _PA_ODR, #1 ; F 318 | rrc a 319 | bccm _PC_ODR, #6 ; G 320 | rrc a 321 | bccm _PD_ODR, #2 ; DP 322 | 323 | dec _led_cur 324 | jrmi 00001$ ; LED #1 325 | jreq 00002$ ; LED #2 326 | 327 | bres _PB_ODR, #4 ; LED #3 328 | jra 00090$ 329 | 330 | 00001$: 331 | bres _PD_ODR, #4 332 | mov _led_cur, #2 333 | jra 00090$ 334 | 335 | 00002$: 336 | bres _PB_ODR, #5 337 | 338 | 00090$: 339 | __endasm; 340 | } 341 | 342 | /****************************************************************************** 343 | * 344 | * Get 7-segment code for ASCII character 345 | */ 346 | 347 | static char code_7seg(char c) 348 | { 349 | if ((c & 0xf0) == 0x30) 350 | return segs_w12_digits[c & 0x0f]; 351 | if (c >= 'A' && 352 | c <= 'U') 353 | return segs_w12_alpha[c - 'A']; 354 | 355 | if (c == ' ') 356 | return 0; 357 | if (c == '-') 358 | return 0x40; 359 | if (c == '_') 360 | return 8; 361 | if (c == '[') 362 | return 0x39; 363 | if (c == ']') 364 | return 0x0f; 365 | 366 | return SEG_INVALID; 367 | } 368 | 369 | /****************************************************************************** 370 | * 371 | * aaa 000 372 | * f b 5 1 373 | * f b 5 1 374 | * ggg 666 375 | * e c 4 2 376 | * e c 4 2 377 | * ddd h 333 7 378 | */ 379 | 380 | const char segs_w12_digits[16] = { 381 | 0x3f, 0x06, 0x5b, 0x4f, 0x66, /* 0 - 4 */ 382 | 0x6d, 0x7d, 0x07, 0x7f, 0x67, /* 5 - 9 */ 383 | SEG_INVALID, SEG_INVALID, SEG_INVALID, 0x48, SEG_INVALID, SEG_INVALID 384 | }; 385 | const char segs_w12_alpha[21] = { 386 | 0x77, /* A */ 387 | 0x7c, /* B */ 388 | 0x39, /* C */ 389 | 0x5e, /* D */ 390 | 0x79, /* E */ 391 | 0x71, /* F */ 392 | SEG_INVALID, /* G */ 393 | 0x76, /* H */ 394 | 0x06, /* I shared with 1 */ 395 | 0x0e, /* J */ 396 | SEG_INVALID, /* K */ 397 | 0x38, /* L */ 398 | SEG_INVALID, /* M */ 399 | 0x54, /* N (small n) */ 400 | 0x5c, /* O (small o) */ 401 | 0x73, /* P */ 402 | SEG_INVALID, /* Q */ 403 | 0x50, /* R (small r) */ 404 | 0x6d, /* S shared with 5 */ 405 | 0x78, /* T (small t) */ 406 | 0x3e /* U */ 407 | }; 408 | 409 | /****************************************************************************** 410 | * 411 | * Board layout: 412 | * Source: https://github.com/TG9541/stm8ef/wiki/Board-W1209 413 | 414 | 1 PD4 7S-Dig1 (200R) 415 | 2 PD5 7S-A 416 | 3 PD6 Rx,AIN6 ((5.0V-20k)-AIN6-(NTC10k||470nF)-GND) 417 | 4 NRST J2.3 418 | 5 PA1 7S-B 419 | 6 PA2 7S-F 420 | 7 VSS GND 421 | 8 Vcap C 422 | 9 VDD +5.0V 423 | 10 PA3 Relay (1:on) 2k/10k-NPN,Relay,LED 424 | 11 PB5 7S-Dig2 (200R) 425 | 12 PB4 7S-Dig3 (200R) 426 | 13 PC3 Key "set" 427 | 14 PC4 Key "+" 428 | 15 PC5 Key "-" 429 | 16 PC6 7S-G 430 | 17 PC7 7S-C 431 | 18 PD1 7S-E / SWIM J.2 432 | 19 PD2 7S-DP 433 | 20 PD3 7S-D 434 | 435 | LED: 436 | 437 | D4 LED #1 anode 438 | B5 LED #2 anode 439 | B4 LED #3 anode 440 | 441 | A D5 442 | B A1 443 | C C7 444 | D D3 445 | E D1 446 | F A2 447 | G C6 448 | DP D2 449 | 450 | KEYS: 451 | 452 | SET C3 453 | + C4 454 | - C5 455 | 456 | RELAY: A3 457 | 458 | 459 | 460 | */ 461 | -------------------------------------------------------------------------------- /lib_w1209.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File name: lib_w1209.h 3 | * Date first: 01/22/2019 4 | * Date last: 02/23/2019 5 | * 6 | * Description: STM8 Library for W1209 thermostat board. 7 | * 8 | * Author: Richard Hodges 9 | * 10 | * Copyright (C) 2019 Richard Hodges. All rights reserved. 11 | * Permission is hereby granted for any use. 12 | * 13 | ****************************************************************************** 14 | * 15 | * Configuration 16 | */ 17 | 18 | #define KB_SIZE 4 /* size of key buffer */ 19 | #define KB_DEBOUNCE 40 /* debounce count in milliseconds */ 20 | #define LED_UPDATE 5 /* milliseconds between LED updates */ 21 | 22 | /* 23 | * Initialize board 24 | */ 25 | 26 | void w12_init(void); 27 | 28 | /* 29 | * Write digit/char to LED 30 | * in: ASCII digit or char (use bit-7 for decimal point) 31 | */ 32 | 33 | void w12_putc(char); 34 | 35 | /* 36 | * Write string to LED 37 | * in: ASCII string (insert decimal point where desired.) 38 | */ 39 | 40 | void w12_puts(char *); 41 | 42 | /* 43 | * Set cursor position 44 | * in: column (0-2) 45 | */ 46 | 47 | void w12_curs(char); 48 | 49 | /* 50 | * Set LED blinking 51 | * in: Blink rate * 1/100 second or 0 (disable) 52 | */ 53 | void w12_blink(char); 54 | 55 | /* 56 | * Get keypress 57 | * out: zero or ASCII key ('0' to '2'), bit-7 set if released 58 | */ 59 | 60 | char w12_getc(void); 61 | 62 | /* 63 | * Poll for display, keys, and blinking 64 | * (call every millisecond) 65 | */ 66 | void w12_poll(void); 67 | 68 | /* 69 | * Turn the relay on/off 70 | * in: zero = off, non-zero = on 71 | */ 72 | 73 | void w12_relay(char); 74 | 75 | /* 76 | * Get the current temperature probe value 77 | * out: current A/D value, -1 if timeout 78 | */ 79 | 80 | short w12_probe(void); 81 | -------------------------------------------------------------------------------- /stm8_103.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for STM8S 103 3 | */ 4 | #ifndef STM8103 5 | #define STM8103 6 | #endif 7 | 8 | #define PTR(addr) *(volatile char *)(addr) 9 | 10 | #define EEPROM PTR(0x4000) 11 | #define EEPROM_SIZE 640 12 | 13 | #define FLASH_BASE PTR(0x8000) 14 | #define FLASH_SIZE 8192 15 | #define FLASH_BLOCK 64 16 | 17 | #define OPT2 PTR(0x4803) // Alternate function remap 18 | #define NOPT2 PTR(0x4804) 19 | 20 | #define UNIQUE_ID PTR(0x4865) // 12-byte unique id 21 | 22 | #define PA_ODR PTR(0x5000) // Port A output latch 23 | #define PA_IDR PTR(0x5001) // Port A input status 24 | #define PA_DDR PTR(0x5002) // Port A data direction 25 | #define PA_CR1 PTR(0x5003) // Port A open drain or pull-ups 26 | #define PA_CR2 PTR(0x5004) // Port A output speed or interrupt 27 | 28 | #define PB_ODR PTR(0x5005) 29 | #define PB_IDR PTR(0x5006) 30 | #define PB_DDR PTR(0x5007) 31 | #define PB_CR1 PTR(0x5008) 32 | #define PB_CR2 PTR(0x5009) 33 | 34 | #define PC_ODR PTR(0x500a) 35 | #define PC_IDR PTR(0x500b) 36 | #define PC_DDR PTR(0x500c) 37 | #define PC_CR1 PTR(0x500d) 38 | #define PC_CR2 PTR(0x500e) 39 | 40 | #define PD_ODR PTR(0x500f) 41 | #define PD_IDR PTR(0x5010) 42 | #define PD_DDR PTR(0x5011) 43 | #define PD_CR1 PTR(0x5012) 44 | #define PD_CR2 PTR(0x5013) 45 | 46 | #define PE_ODR PTR(0x5014) 47 | #define PE_IDR PTR(0x5015) 48 | #define PE_DDR PTR(0x5016) 49 | #define PE_CR1 PTR(0x5017) 50 | #define PE_CR2 PTR(0x5018) 51 | 52 | #define PF_ODR PTR(0x5019) 53 | #define PF_IDR PTR(0x501a) 54 | #define PF_DDR PTR(0x501b) 55 | #define PF_CR1 PTR(0x501c) 56 | #define PF_CR2 PTR(0x501d) 57 | 58 | #define FLASH_CR1 PTR(0x505a) // Flash control 1 59 | #define FLASH_CR2 PTR(0x505b) // Flash control 2 60 | #define FLASH_NCR2 PTR(0x505c) // Flash control 2 complement 61 | #define FLASH_FPR PTR(0x505d) // Flash protection 62 | #define FLASH_NFPR PTR(0x505e) // Flash protection complement 63 | #define FLASH_IAPSR PTR(0x505f) // Flash in-application program status 64 | #define FLASH_PUKR PTR(0x5062) // Flash unprotect 65 | #define FLASH_DUKR PTR(0x5064) // Data EEPROM unprotect 66 | 67 | #define EXTI_CR1 PTR(0x50a0) // External interrupt control 68 | #define EXTI_CR2 PTR(0x50a1) 69 | 70 | #define CLK_ICKR PTR(0x50c0) // Internal clock control 71 | #define CLK_ECKR PTR(0x50c1) // External clock control 72 | #define CLK_CMSR PTR(0x50c3) // Clock master status 73 | #define CLK_SWR PTR(0x50c4) // Clock master switch 74 | #define CLK_SWCR PTR(0x50c5) // Clock switch control 75 | #define CLK_CKDIVR PTR(0x50c6) // Clock divider 76 | #define CLK_PCKENR1 PTR(0x50c7) // Peripheral clock gating #1 77 | #define CLK_CSSR PTR(0x50c8) // Clock security system 78 | #define CLK_CCOR PTR(0x50c9) // Configurable clock control 79 | #define CLK_PCKENR2 PTR(0x50ca) // Peripheral clock gating #2 80 | #define CLK_HSITRIMR PTR(0x50cc) // HSI clock calibration trimming 81 | #define CLK_SWIMCCR PTR(0x50cd) // SWIM clock control 82 | 83 | #define BEEP_CSR PTR(0x50f3) // BEEP control 84 | 85 | #define SPI_CR1 PTR(0x5200) // SPI control #1 86 | #define SPI_CR2 PTR(0x5201) // SPI control #2 87 | #define SPI_ICR PTR(0x5202) // SPI interrupt control 88 | #define SPI_SR PTR(0x5203) // SPI status 89 | #define SPI_DR PTR(0x5204) // SPI data R/W 90 | #define SPI_CRCPR PTR(0x5205) // SPI CRC polynomial 91 | #define SPI_RXCRCR PTR(0x5206) // SPI RX CRC 92 | #define SPI_TXCRCR PTR(0x5207) // SPI TX CRC 93 | 94 | #define SPI_CR1_SPE 0x40 // SPI enable 95 | #define SPI_CR2_BDM 0x80 // Bidirectional (one data wire for read and write) 96 | #define SPI_CR2_BDOE 0x40 // Bidirectional output enable (transmitting) 97 | #define SPI_CR2_RXONLY 0x04 // Enable SPI clock for receiving 98 | #define SPI_ICR_TXIE 0x80 // TX interrupt enable 99 | #define SPI_ICR_RXIE 0x40 // RX interrupt enable 100 | #define SPI_SR_BSY 0x80 // Busy 101 | #define SPI_SR_TXE 0x02 // TX buffer empty 102 | #define SPI_SR_RXNE 0x01 // RX buffer not empty 103 | 104 | #define UART1_SR PTR(0x5230) // UART1 status 105 | #define UART1_DR PTR(0x5231) // UART1 data 106 | #define UART1_BRR1 PTR(0x5232) // UART1 baud rate #1 107 | #define UART1_BRR2 PTR(0x5233) // UART1 baud rate #2 108 | #define UART1_CR1 PTR(0x5234) // UART1 control #1 109 | #define UART1_CR2 PTR(0x5235) // UART1 control #2 110 | #define UART1_CR3 PTR(0x5236) // UART1 control #3 111 | #define UART1_CR4 PTR(0x5237) // UART1 control #4 112 | #define UART1_CR5 PTR(0x5238) // UART1 control #5 113 | #define UART1_GTR PTR(0x5239) // UART1 guard time 114 | #define UART1_PSCR PTR(0x523a) // UART1 prescaler 115 | 116 | #define SR_OR (1 << 3) 117 | #define SR_TXE (1 << 7) 118 | 119 | #define TIM1_CR1 PTR(0x5250) // TIM1 Control 1 120 | #define TIM1_CR2 PTR(0x5251) // TIM1 Control 2 121 | #define TIM1_SMCR PTR(0x5252) // TIM1 Slave mode control 122 | #define TIM1_ETR PTR(0x5253) // TIM1 External trigger 123 | #define TIM1_IER PTR(0x5254) // TIM1 Interrupt enable 124 | #define TIM1_SR1 PTR(0x5255) // TIM1 status 1 125 | #define TIM1_SR2 PTR(0x5256) // TIM1 status 2 126 | #define TIM1_EGR PTR(0x5257) // TIM1 Event generation 127 | #define TIM1_CCMR1 PTR(0x5258) // TIM1 Capture/compare mode 1 128 | #define TIM1_CCMR2 PTR(0x5259) // TIM1 Capture/compare mode 2 129 | #define TIM1_CCMR3 PTR(0x525a) // TIM1 Capture/compare mode 3 130 | #define TIM1_CCMR4 PTR(0x525b) // TIM1 Capture/compare mode 4 131 | #define TIM1_CCER1 PTR(0x525c) // TIM1 Capture/compare enable 1 132 | #define TIM1_CCER2 PTR(0x525d) // TIM1 Capture/compare enable 2 133 | #define TIM1_CNTRH PTR(0x525e) // TIM1 Counter high 134 | #define TIM1_CNTRL PTR(0x525f) // TIM1 Counter low 135 | #define TIM1_PSCRH PTR(0x5260) // TIM1 Prescale high 136 | #define TIM1_PSCRL PTR(0x5261) // TIM1 Prescale low 137 | #define TIM1_ARRH PTR(0x5262) // TIM1 Auto reload high 138 | #define TIM1_ARRL PTR(0x5263) // TIM1 Auto reload low 139 | #define TIM1_RCR PTR(0x5264) // TIM1 Repetition counter 140 | #define TIM1_CCR1H PTR(0x5265) // TIM1 Capture/compare 1 high 141 | #define TIM1_CCR1L PTR(0x5266) // TIM1 Capture/compare 1 low 142 | #define TIM1_CCR2H PTR(0x5267) // TIM1 Capture/compare 2 high 143 | #define TIM1_CCR2L PTR(0x5268) // TIM1 Capture/compare 2 low 144 | #define TIM1_CCR3H PTR(0x5269) // TIM1 Capture/compare 3 high 145 | #define TIM1_CCR3L PTR(0x526a) // TIM1 Capture/compare 3 low 146 | #define TIM1_CCR4H PTR(0x526b) // TIM1 Capture/compare 4 high 147 | #define TIM1_CCR4L PTR(0x526c) // TIM1 Capture/compare 4 low 148 | #define TIM1_BKR PTR(0x526d) // TIM1 Break register 149 | #define TIM1_DTR PTR(0x526e) // TIM1 Dead time register 150 | #define TIM1_OISR PTR(0x526f) // TIM1 Output idle state 151 | 152 | #define TIM2_CR1 PTR(0x5300) // TIM2 Control 1 153 | #define TIM2_IER PTR(0x5303) // TIM2 Interrupt enable 154 | #define TIM2_SR1 PTR(0x5304) // TIM2 Status 1 155 | #define TIM2_SR2 PTR(0x5305) // TIM2 Status 2 156 | #define TIM2_EGR PTR(0x5306) // TIM2 Event generation 157 | #define TIM2_CCMR1 PTR(0x5307) // TIM2 cap/comp mode 1 158 | #define TIM2_CCMR2 PTR(0x5308) // TIM2 cap/comp mode 2 159 | #define TIM2_CCMR3 PTR(0x5309) // TIM2 cap/comp mode 3 160 | #define TIM2_CCER1 PTR(0x530a) // TIM2 cap/comp enable 1 161 | #define TIM2_CCER2 PTR(0x530b) // TIM2 cap/comp enable 2 162 | #define TIM2_CNTRH PTR(0x530c) // TIM2 counter high 163 | #define TIM2_CNTRL PTR(0x530d) // TIM2 counter low 164 | #define TIM2_PSCR PTR(0x530e) // TIM2 prescaler 165 | #define TIM2_ARRH PTR(0x530f) // TIM2 auto-reload high 166 | #define TIM2_ARRL PTR(0x5310) // TIM2 auto-reload low 167 | #define TIM2_CCR1H PTR(0x5311) // TIM2 cap/comp 1 high 168 | #define TIM2_CCR1L PTR(0x5312) // TIM2 cap/comp 1 low 169 | #define TIM2_CCR2H PTR(0x5313) // TIM2 cap/comp 2 high 170 | #define TIM2_CCR2L PTR(0x5314) // TIM2 cap/comp 2 low 171 | #define TIM2_CCR3H PTR(0x5315) // TIM2 cap/comp 3 high 172 | #define TIM2_CCR3L PTR(0x5316) // TIM2 cap/comp 3 low 173 | 174 | #define TIMx_CEN (1 << 0) // counter enable 175 | #define TIMx_UIE (1 << 0) // update interrupt 176 | #define TIMx_CC1IE (1 << 1) // capture/compare 1 interrupt 177 | #define TIMx_CC2IE (1 << 2) // capture/compare 2 interrupt 178 | #define TIMx_CC3IE (1 << 3) // capture/compare 3 interrupt 179 | #define TIMx_CC1E (1 << 0) // capture 1 enable 180 | #define TIMx_CC1G (1 << 1) // capture/compare 1 generation 181 | #define TIMx_CC1P (1 << 1) // capture/compare 1 polarity 182 | 183 | #define TIM4_CR1 PTR(0x5340) // TIM4 control 1 184 | #define TIM4_IER PTR(0x5343) // TIM4 interrupt enable 185 | #define TIM4_SR PTR(0x5344) // TIM4 status 186 | #define TIM4_EGR PTR(0x5345) // TIM4 event generation 187 | #define TIM4_CNTR PTR(0x5346) // TIM4 counter 188 | #define TIM4_PSCR PTR(0x5347) // TIM4 prescaler 189 | #define TIM4_ARR PTR(0x5348) // TIM4 auto reload 190 | 191 | #define ADC_DB0RH PTR(0x53e0) // ADC data buffer 0 high 192 | #define ADC_DB0RL PTR(0x53e1) // ADC data buffer 0 low 193 | 194 | #define ADC_CSR PTR(0x5400) // ADC control/status 195 | #define ADC_CR1 PTR(0x5401) // ADC config reg 1 196 | #define ADC_CR2 PTR(0x5402) // ADC config reg 2 197 | #define ADC_CR3 PTR(0x5403) // ADC config reg 3 198 | #define ADC_DRH PTR(0x5404) // ADC data register high 199 | #define ADC_DRL PTR(0x5405) // ADC data register low 200 | #define ADC_TDRH PTR(0x5406) // ADC Schmitt trigger disable high 201 | #define ADC_TDRL PTR(0x5407) // ADC Schmitt trigger disable low 202 | #define ADC_HTRH PTR(0x5408) // ADC high threshold high 203 | #define ADC_HTRL PTR(0x5409) // ADC high trheshold low 204 | #define ADC_LTRH PTR(0x540a) // ADC low threshold high 205 | #define ADC_LTRL PTR(0x540b) // ADC low threshold low 206 | #define ADC_AWSRH PTR(0x540c) // ADC watchdog status high 207 | #define ADC_AWSRL PTR(0x540d) // ADC watchdog status low 208 | #define ADC_AWCRH PTR(0x540e) // ADC watchdog control high 209 | #define ADC_AWCRL PTR(0x540f) // ADC watchdog control low 210 | 211 | -------------------------------------------------------------------------------- /stm8_103.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * STM8 defines for inline assembly. 3 | * Names are preceded with underscore. 4 | */ 5 | 6 | #define _OPT2 0x4803 // Alternate function remap 7 | #define _NOPT2 0x4804 8 | 9 | #define _UNIQUE_ID 0x4865 // 12-byte unique id 10 | 11 | #define _PA_ODR 0x5000 12 | #define _PA_IDR 0x5001 13 | #define _PA_DDR 0x5002 14 | #define _PA_CR1 0x5003 15 | #define _PA_CR2 0x5004 16 | 17 | #define _PB_ODR 0x5005 18 | #define _PB_IDR 0x5006 19 | #define _PB_DDR 0x5007 20 | #define _PB_CR1 0x5008 21 | #define _PB_CR2 0x5009 22 | 23 | #define _PC_ODR 0x500a 24 | #define _PC_IDR 0x500b 25 | #define _PC_DDR 0x500c 26 | #define _PC_CR1 0x500d 27 | #define _PC_CR2 0x500e 28 | 29 | #define _PD_ODR 0x500f 30 | #define _PD_IDR 0x5010 31 | #define _PD_DDR 0x5011 32 | #define _PD_CR1 0x5012 33 | #define _PD_CR2 0x5013 34 | 35 | #define _PE_ODR 0x5014 36 | #define _PE_IDR 0x5015 37 | #define _PE_DDR 0x5016 38 | #define _PE_CR1 0x5017 39 | #define _PE_CR2 0x5018 40 | 41 | #define _PF_ODR 0x5019 42 | #define _PF_IDR 0x501a 43 | #define _PF_DDR 0x501b 44 | #define _PF_CR1 0x501c 45 | #define _PF_CR2 0x501d 46 | 47 | #define _FLASH_CR1 0x505a // Flash control 1 48 | #define _FLASH_CR2 0x505b // Flash control 2 49 | #define _FLASH_NCR2 0x505c // Flash control 2 complement 50 | #define _FLASH_FPR 0x505d // Flash protection 51 | #define _FLASH_NFPR 0x505e // Flash protection complement 52 | #define _FLASH_IAPSR 0x505f // Flash control 1 53 | #define _FLASH_PUKR 0x5062 // Flash in-application program status 54 | #define _FLASH_DUKR 0x5064 // Data EEPROM unprotect 55 | 56 | #define _EXTI_CR1 0x50a0 57 | #define _EXTI_CR2 0x50a1 58 | 59 | #define _SPI_CR1 0x5200 // SPI control #1 60 | #define _SPI_CR2 0x5201 // SPI control #2 61 | #define _SPI_ICR 0x5202 // SPI interrupt control 62 | #define _SPI_SR 0x5203 // SPI status 63 | #define _SPI_DR 0x5204 // SPI data R/W 64 | #define _SPI_CRCPR 0x5205 // SPI CRC polynomial 65 | #define _SPI_RXCRCR 0x5206 // SPI RX CRC 66 | #define _SPI_TXCRCR 0x5207 // SPI TX CRC 67 | 68 | #define _TIM1_CR1 0x5250 // TIM1 Control 1 69 | #define _TIM1_CR2 0x5251 // TIM1 Control 2 70 | #define _TIM1_SMCR 0x5252 // TIM1 Slave mode control 71 | #define _TIM1_ETR 0x5253 // TIM1 External trigger 72 | #define _TIM1_IER 0x5254 // TIM1 Interrupt enable 73 | #define _TIM1_SR1 0x5255 // TIM1 status 1 74 | #define _TIM1_SR2 0x5256 // TIM1 status 2 75 | #define _TIM1_EGR 0x5257 // TIM1 Event generation 76 | #define _TIM1_CCMR1 0x5258 // TIM1 Capture/compare mode 1 77 | #define _TIM1_CCMR2 0x5259 // TIM1 Capture/compare mode 2 78 | #define _TIM1_CCMR3 0x525a // TIM1 Capture/compare mode 3 79 | #define _TIM1_CCMR4 0x525b // TIM1 Capture/compare mode 4 80 | #define _TIM1_CCER1 0x525c // TIM1 Capture/compare enable 1 81 | #define _TIM1_CCER2 0x525d // TIM1 Capture/compare enable 2 82 | #define _TIM1_CNTRH 0x525e // TIM1 Counter high 83 | #define _TIM1_CNTRL 0x525f // TIM1 Counter low 84 | #define _TIM1_PSCRH 0x5260 // TIM1 Prescale high 85 | #define _TIM1_PSCRL 0x5261 // TIM1 Prescale low 86 | #define _TIM1_ARRH 0x5262 // TIM1 Auto reload high 87 | #define _TIM1_ARRL 0x5263 // TIM1 Auto reload low 88 | #define _TIM1_RCR 0x5264 // TIM1 Repetition counter 89 | #define _TIM1_CCR1H 0x5265 // TIM1 Capture/compare 1 high 90 | #define _TIM1_CCR1L 0x5266 // TIM1 Capture/compare 1 low 91 | #define _TIM1_CCR2H 0x5267 // TIM1 Capture/compare 2 high 92 | #define _TIM1_CCR2L 0x5268 // TIM1 Capture/compare 2 low 93 | #define _TIM1_CCR3H 0x5269 // TIM1 Capture/compare 3 high 94 | #define _TIM1_CCR3L 0x526a // TIM1 Capture/compare 3 low 95 | #define _TIM1_CCR4H 0x526b // TIM1 Capture/compare 4 high 96 | #define _TIM1_CCR4L 0x526c // TIM1 Capture/compare 4 low 97 | #define _TIM1_BKR 0x526d // TIM1 Break register 98 | #define _TIM1_DTR 0x526e // TIM1 Dead time register 99 | #define _TIM1_OISR 0x526f // TIM1 Output idle state 100 | 101 | #define _TIM2_CR1 0x5300 // TIM2 Control 1 102 | #define _TIM2_IER 0x5303 // TIM2 Interrupt enable 103 | #define _TIM2_SR1 0x5304 // TIM2 Status 1 104 | #define _TIM2_SR2 0x5305 // TIM2 Status 2 105 | #define _TIM2_EGR 0x5306 // TIM2 Event generation 106 | #define _TIM2_CCMR1 0x5307 // TIM2 cap/comp mode 1 107 | #define _TIM2_CCMR2 0x5308 // TIM2 cap/comp mode 2 108 | #define _TIM2_CCMR3 0x5309 // TIM2 cap/comp mode 3 109 | #define _TIM2_CCER1 0x530a // TIM2 cap/comp enable 1 110 | #define _TIM2_CCER2 0x530b // TIM2 cap/comp enable 2 111 | #define _TIM2_CNTRH 0x530c // TIM2 counter high 112 | #define _TIM2_CNTRL 0x530d // TIM2 counter low 113 | #define _TIM2_PSCR 0x530e // TIM2 prescaler 114 | #define _TIM2_ARRH 0x530f // TIM2 auto-reload high 115 | #define _TIM2_ARRL 0x5310 // TIM2 auto-reload low 116 | #define _TIM2_CCR1H 0x5311 // TIM2 cap/comp 1 high 117 | #define _TIM2_CCR1L 0x5312 // TIM2 cap/comp 1 low 118 | #define _TIM2_CCR2H 0x5313 // TIM2 cap/comp 2 high 119 | #define _TIM2_CCR2L 0x5314 // TIM2 cap/comp 2 low 120 | #define _TIM2_CCR3H 0x5315 // TIM2 cap/comp 3 high 121 | #define _TIM2_CCR3L 0x5316 // TIM2 cap/comp 3 low 122 | 123 | #define _ADC_DB0RH 0x53e0 // ADC data buffer 0 high 124 | #define _ADC_DB0RL 0x53e1 // ADC data buffer 0 low 125 | 126 | #define _ADC_CSR 0x5400 // ADC control/status 127 | #define _ADC_CR1 0x5401 // ADC config reg 1 128 | #define _ADC_CR2 0x5402 // ADC config reg 2 129 | #define _ADC_CR3 0x5403 // ADC config reg 3 130 | #define _ADC_DRH 0x5404 // ADC data register high 131 | #define _ADC_DRL 0x5405 // ADC data register low 132 | #define _ADC_TDRH 0x5406 // ADC Schmitt trigger disable high 133 | #define _ADC_TDRL 0x5407 // ADC Schmitt trigger disable low 134 | #define _ADC_HTRH 0x5408 // ADC high threshold high 135 | #define _ADC_HTRL 0x5409 // ADC high trheshold low 136 | #define _ADC_LTRH 0x540a // ADC low threshold high 137 | #define _ADC_LTRL 0x540b // ADC low threshold low 138 | #define _ADC_AWSRH 0x540c // ADC watchdog status high 139 | #define _ADC_AWSRL 0x540d // ADC watchdog status low 140 | #define _ADC_AWCRH 0x540e // ADC watchdog control high 141 | #define _ADC_AWCRL 0x540f // ADC watchdog control low 142 | 143 | #define _ITC_SPR1 0x7f70 144 | #define _ITC_SPR2 0x7f71 145 | #define _ITC_SPR3 0x7f72 146 | #define _ITC_SPR4 0x7f73 147 | #define _ITC_SPR5 0x7f74 148 | #define _ITC_SPR6 0x7f75 149 | #define _ITC_SPR7 0x7f76 150 | #define _ITC_SPR8 0x7f77 151 | 152 | -------------------------------------------------------------------------------- /stm8_105.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for STM8S 105 3 | */ 4 | #ifndef STM8105 5 | #define STM8105 6 | #endif 7 | 8 | #define PTR(addr) *(volatile char *)(addr) 9 | 10 | #define EEPROM PTR(0x4000) 11 | #define EEPROM_SIZE 1024 12 | 13 | #define FLASH_BASE PTR(0x8000) 14 | #define FLASH_SIZE 16834 15 | #define FLASH_BLOCK 128 16 | 17 | #define OPT2 PTR(0x4803) // Alternate function remap 18 | #define NOPT2 PTR(0x4804) 19 | 20 | #define UNIQUE_ID PTR(0x48cd) // 12-byte unique id 21 | 22 | #define PA_ODR PTR(0x5000) // Port A output latch 23 | #define PA_IDR PTR(0x5001) // Port A input status 24 | #define PA_DDR PTR(0x5002) // Port A data direction 25 | #define PA_CR1 PTR(0x5003) // Port A open drain or pull-ups 26 | #define PA_CR2 PTR(0x5004) // Port A output speed or interrupt 27 | 28 | #define PB_ODR PTR(0x5005) 29 | #define PB_IDR PTR(0x5006) 30 | #define PB_DDR PTR(0x5007) 31 | #define PB_CR1 PTR(0x5008) 32 | #define PB_CR2 PTR(0x5009) 33 | 34 | #define PC_ODR PTR(0x500a) 35 | #define PC_IDR PTR(0x500b) 36 | #define PC_DDR PTR(0x500c) 37 | #define PC_CR1 PTR(0x500d) 38 | #define PC_CR2 PTR(0x500e) 39 | 40 | #define PD_ODR PTR(0x500f) 41 | #define PD_IDR PTR(0x5010) 42 | #define PD_DDR PTR(0x5011) 43 | #define PD_CR1 PTR(0x5012) 44 | #define PD_CR2 PTR(0x5013) 45 | 46 | #define PE_ODR PTR(0x5014) 47 | #define PE_IDR PTR(0x5015) 48 | #define PE_DDR PTR(0x5016) 49 | #define PE_CR1 PTR(0x5017) 50 | #define PE_CR2 PTR(0x5018) 51 | 52 | #define PF_ODR PTR(0x5019) 53 | #define PF_IDR PTR(0x501a) 54 | #define PF_DDR PTR(0x501b) 55 | #define PF_CR1 PTR(0x501c) 56 | #define PF_CR2 PTR(0x501d) 57 | 58 | #define PG_ODR PTR(0x501e) 59 | #define PG_IDR PTR(0x501f) 60 | #define PG_DDR PTR(0x5020) 61 | #define PG_CR1 PTR(0x5021) 62 | #define PG_CR2 PTR(0x5022) 63 | 64 | #define FLASH_CR1 PTR(0x505a) // Flash control 1 65 | #define FLASH_CR2 PTR(0x505b) // Flash control 2 66 | #define FLASH_NCR2 PTR(0x505c) // Flash control 2 complement 67 | #define FLASH_FPR PTR(0x505d) // Flash protection 68 | #define FLASH_NFPR PTR(0x505e) // Flash protection complement 69 | #define FLASH_IAPSR PTR(0x505f) // Flash in-application program status 70 | #define FLASH_PUKR PTR(0x5062) // Flash unprotect 71 | #define FLASH_DUKR PTR(0x5064) // Data EEPROM unprotect 72 | 73 | #define EXTI_CR1 PTR(0x50a0) // External interrupt control 74 | #define EXTI_CR2 PTR(0x50a1) 75 | 76 | #define CLK_ICKR PTR(0x50c0) // Internal clock control 77 | #define CLK_ECKR PTR(0x50c1) // External clock control 78 | #define CLK_CMSR PTR(0x50c3) // Clock master status 79 | #define CLK_SWR PTR(0x50c4) // Clock master switch 80 | #define CLK_SWCR PTR(0x50c5) // Clock switch control 81 | #define CLK_CKDIVR PTR(0x50c6) // Clock divider 82 | #define CLK_PCKENR1 PTR(0x50c7) // Peripheral clock gating #1 83 | #define CLK_CSSR PTR(0x50c8) // Clock security system 84 | #define CLK_CCOR PTR(0x50c9) // Configurable clock control 85 | #define CLK_PCKENR2 PTR(0x50ca) // Peripheral clock gating #2 86 | #define CLK_HSITRIMR PTR(0x50cc) // HSI clock calibration trimming 87 | #define CLK_SWIMCCR PTR(0x50cd) // SWIM clock control 88 | 89 | #define BEEP_CSR PTR(0x50f3) // BEEP control 90 | 91 | #define UART2_SR PTR(0x5240) // UART2 status 92 | #define UART2_DR PTR(0x5241) // UART2 data 93 | #define UART2_BRR1 PTR(0x5242) // UART2 baud rate #1 94 | #define UART2_BRR2 PTR(0x5243) // UART2 baud rate #2 95 | #define UART2_CR1 PTR(0x5244) // UART2 control #1 96 | #define UART2_CR2 PTR(0x5245) // UART2 control #2 97 | #define UART2_CR3 PTR(0x5246) // UART2 control #3 98 | #define UART2_CR4 PTR(0x5247) // UART2 control #4 99 | #define UART2_CR5 PTR(0x5248) // UART2 control #5 100 | #define UART2_CR6 PTR(0x5249) // UART2 control #6 101 | #define UART2_GTR PTR(0x524a) // UART2 guard time 102 | #define UART2_PSCR PTR(0x524b) // UART2 prescaler 103 | 104 | #define SR_OR (1 << 3) 105 | #define SR_TXE (1 << 7) 106 | 107 | #define TIM1_CR1 PTR(0x5250) // TIM1 Control 1 108 | #define TIM1_CR2 PTR(0x5251) // TIM1 Control 2 109 | #define TIM1_SMCR PTR(0x5252) // TIM1 Slave mode control 110 | #define TIM1_ETR PTR(0x5253) // TIM1 External trigger 111 | #define TIM1_IER PTR(0x5254) // TIM1 Interrupt enable 112 | #define TIM1_SR1 PTR(0x5255) // TIM1 status 1 113 | #define TIM1_SR2 PTR(0x5256) // TIM1 status 2 114 | #define TIM1_EGR PTR(0x5257) // TIM1 Event generation 115 | #define TIM1_CCMR1 PTR(0x5258) // TIM1 Capture/compare mode 1 116 | #define TIM1_CCMR2 PTR(0x5259) // TIM1 Capture/compare mode 2 117 | #define TIM1_CCMR3 PTR(0x525a) // TIM1 Capture/compare mode 3 118 | #define TIM1_CCMR4 PTR(0x525b) // TIM1 Capture/compare mode 4 119 | #define TIM1_CCER1 PTR(0x525c) // TIM1 Capture/compare enable 1 120 | #define TIM1_CCER2 PTR(0x525d) // TIM1 Capture/compare enable 2 121 | #define TIM1_CNTRH PTR(0x525e) // TIM1 Counter high 122 | #define TIM1_CNTRL PTR(0x525f) // TIM1 Counter low 123 | #define TIM1_PSCRH PTR(0x5260) // TIM1 Prescale high 124 | #define TIM1_PSCRL PTR(0x5261) // TIM1 Prescale low 125 | #define TIM1_ARRH PTR(0x5262) // TIM1 Auto reload high 126 | #define TIM1_ARRL PTR(0x5263) // TIM1 Auto reload low 127 | #define TIM1_RCR PTR(0x5264) // TIM1 Repetition counter 128 | #define TIM1_CCR1H PTR(0x5265) // TIM1 Capture/compare 1 high 129 | #define TIM1_CCR1L PTR(0x5266) // TIM1 Capture/compare 1 low 130 | #define TIM1_CCR2H PTR(0x5267) // TIM1 Capture/compare 2 high 131 | #define TIM1_CCR2L PTR(0x5268) // TIM1 Capture/compare 2 low 132 | #define TIM1_CCR3H PTR(0x5269) // TIM1 Capture/compare 3 high 133 | #define TIM1_CCR3L PTR(0x526a) // TIM1 Capture/compare 3 low 134 | #define TIM1_CCR4H PTR(0x526b) // TIM1 Capture/compare 4 high 135 | #define TIM1_CCR4L PTR(0x526c) // TIM1 Capture/compare 4 low 136 | #define TIM1_BKR PTR(0x526d) // TIM1 Break register 137 | #define TIM1_DTR PTR(0x526e) // TIM1 Dead time register 138 | #define TIM1_OISR PTR(0x526f) // TIM1 Output idle state 139 | 140 | #define TIM2_CR1 PTR(0x5300) // TIM2 Control 1 141 | #define TIM2_IER PTR(0x5301) // TIM2 Interrupt enable 142 | #define TIM2_SR1 PTR(0x5302) // TIM2 Status 1 143 | #define TIM2_SR2 PTR(0x5303) // TIM2 Status 2 144 | #define TIM2_EGR PTR(0x5304) // TIM2 Event generation 145 | #define TIM2_CCMR1 PTR(0x5305) // TIM2 cap/comp mode 1 146 | #define TIM2_CCMR2 PTR(0x5306) // TIM2 cap/comp mode 2 147 | #define TIM2_CCMR3 PTR(0x5307) // TIM2 cap/comp mode 3 148 | #define TIM2_CCER1 PTR(0x5308) // TIM2 cap/comp enable 1 149 | #define TIM2_CCER2 PTR(0x5309) // TIM2 cap/comp enable 2 150 | #define TIM2_CNTRH PTR(0x530a) // TIM2 counter high 151 | #define TIM2_CNTRL PTR(0x530b) // TIM2 counter low 152 | #define TIM2_PSCR PTR(0x530c) // TIM2 prescaler 153 | #define TIM2_ARRH PTR(0x530d) // TIM2 auto-reload high 154 | #define TIM2_ARRL PTR(0x530e) // TIM2 auto-reload low 155 | #define TIM2_CCR1H PTR(0x530f) // TIM2 cap/comp 1 high 156 | #define TIM2_CCR1L PTR(0x5310) // TIM2 cap/comp 1 low 157 | #define TIM2_CCR2H PTR(0x5311) // TIM2 cap/comp 2 high 158 | #define TIM2_CCR2L PTR(0x5312) // TIM2 cap/comp 2 low 159 | #define TIM2_CCR3H PTR(0x5313) // TIM2 cap/comp 3 high 160 | #define TIM2_CCR3L PTR(0x5314) // TIM2 cap/comp 3 low 161 | 162 | #define TIMx_CEN (1 << 0) // counter enable 163 | #define TIMx_UIE (1 << 0) // update interrupt 164 | #define TIMx_CC1IE (1 << 1) // capture/compare 1 interrupt 165 | #define TIMx_CC2IE (1 << 2) // capture/compare 2 interrupt 166 | #define TIMx_CC3IE (1 << 3) // capture/compare 3 interrupt 167 | #define TIMx_CC1E (1 << 0) // capture 1 enable 168 | #define TIMx_CC1G (1 << 1) // capture/compare 1 generation 169 | #define TIMx_CC1P (1 << 1) // capture/compare 1 polarity 170 | 171 | #define TIM4_CR1 PTR(0x5340) // TIM4 control 1 172 | #define TIM4_IER PTR(0x5341) // TIM4 interrupt enable 173 | #define TIM4_SR PTR(0x5342) // TIM4 status 174 | #define TIM4_EGR PTR(0x5343) // TIM4 event generation 175 | #define TIM4_CNTR PTR(0x5344) // TIM4 counter 176 | #define TIM4_PSCR PTR(0x5345) // TIM4 prescaler 177 | #define TIM4_ARR PTR(0x5346) // TIM4 auto reload 178 | 179 | #define ADC_DB0RH PTR(0x53e0) // ADC data buffer 0 high 180 | #define ADC_DB0RL PTR(0x53e1) // ADC data buffer 0 low 181 | 182 | #define ADC_CSR PTR(0x5400) // ADC control/status 183 | #define ADC_CR1 PTR(0x5401) // ADC config reg 1 184 | #define ADC_CR2 PTR(0x5402) // ADC config reg 2 185 | #define ADC_CR3 PTR(0x5403) // ADC config reg 3 186 | #define ADC_DRH PTR(0x5404) // ADC data register high 187 | #define ADC_DRL PTR(0x5405) // ADC data register low 188 | #define ADC_TDRH PTR(0x5406) // ADC Schmitt trigger disable high 189 | #define ADC_TDRL PTR(0x5407) // ADC Schmitt trigger disable low 190 | #define ADC_HTRH PTR(0x5408) // ADC high threshold high 191 | #define ADC_HTRL PTR(0x5409) // ADC high trheshold low 192 | #define ADC_LTRH PTR(0x540a) // ADC low threshold high 193 | #define ADC_LTRL PTR(0x540b) // ADC low threshold low 194 | #define ADC_AWSRH PTR(0x540c) // ADC watchdog status high 195 | #define ADC_AWSRL PTR(0x540d) // ADC watchdog status low 196 | #define ADC_AWCRH PTR(0x540e) // ADC watchdog control high 197 | #define ADC_AWCRL PTR(0x540f) // ADC watchdog control low 198 | 199 | -------------------------------------------------------------------------------- /stm8_105.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * STM8 defines for stm8s_105 inline assembly. 3 | * Names are preceded with underscore. 4 | */ 5 | 6 | #define _OPT2 0x4803 // Alternate function remap 7 | #define _NOPT2 0x4804 8 | 9 | #define _UNIQUE_ID 0x48cd // 12-byte unique id 10 | 11 | #define _PA_ODR 0x5000 12 | #define _PA_IDR 0x5001 13 | #define _PA_DDR 0x5002 14 | #define _PA_CR1 0x5003 15 | #define _PA_CR2 0x5004 16 | 17 | #define _PB_ODR 0x5005 18 | #define _PB_IDR 0x5006 19 | #define _PB_DDR 0x5007 20 | #define _PB_CR1 0x5008 21 | #define _PB_CR2 0x5009 22 | 23 | #define _PC_ODR 0x500a 24 | #define _PC_IDR 0x500b 25 | #define _PC_DDR 0x500c 26 | #define _PC_CR1 0x500d 27 | #define _PC_CR2 0x500e 28 | 29 | #define _PD_ODR 0x500f 30 | #define _PD_IDR 0x5010 31 | #define _PD_DDR 0x5011 32 | #define _PD_CR1 0x5012 33 | #define _PD_CR2 0x5013 34 | 35 | #define _PE_ODR 0x5014 36 | #define _PE_IDR 0x5015 37 | #define _PE_DDR 0x5016 38 | #define _PE_CR1 0x5017 39 | #define _PE_CR2 0x5018 40 | 41 | #define _PF_ODR 0x5019 42 | #define _PF_IDR 0x501a 43 | #define _PF_DDR 0x501b 44 | #define _PF_CR1 0x501c 45 | #define _PF_CR2 0x501d 46 | 47 | #define _FLASH_CR1 0x505a // Flash control 1 48 | #define _FLASH_CR2 0x505b // Flash control 2 49 | #define _FLASH_NCR2 0x505c // Flash control 2 complement 50 | #define _FLASH_FPR 0x505d // Flash protection 51 | #define _FLASH_NFPR 0x505e // Flash protection complement 52 | #define _FLASH_IAPSR 0x505f // Flash control 1 53 | #define _FLASH_PUKR 0x5062 // Flash in-application program status 54 | #define _FLASH_DUKR 0x5064 // Data EEPROM unprotect 55 | 56 | #define _EXTI_CR1 0x50a0 57 | #define _EXTI_CR2 0x50a1 58 | 59 | #define _TIM1_CR1 0x5250 // TIM1 Control 1 60 | #define _TIM1_CR2 0x5251 // TIM1 Control 2 61 | #define _TIM1_SMCR 0x5252 // TIM1 Slave mode control 62 | #define _TIM1_ETR 0x5253 // TIM1 External trigger 63 | #define _TIM1_IER 0x5254 // TIM1 Interrupt enable 64 | #define _TIM1_SR1 0x5255 // TIM1 status 1 65 | #define _TIM1_SR2 0x5256 // TIM1 status 2 66 | #define _TIM1_EGR 0x5257 // TIM1 Event generation 67 | #define _TIM1_CCMR1 0x5258 // TIM1 Capture/compare mode 1 68 | #define _TIM1_CCMR2 0x5259 // TIM1 Capture/compare mode 2 69 | #define _TIM1_CCMR3 0x525a // TIM1 Capture/compare mode 3 70 | #define _TIM1_CCMR4 0x525b // TIM1 Capture/compare mode 4 71 | #define _TIM1_CCER1 0x525c // TIM1 Capture/compare enable 1 72 | #define _TIM1_CCER2 0x525d // TIM1 Capture/compare enable 2 73 | #define _TIM1_CNTRH 0x525e // TIM1 Counter high 74 | #define _TIM1_CNTRL 0x525f // TIM1 Counter low 75 | #define _TIM1_PSCRH 0x5260 // TIM1 Prescale high 76 | #define _TIM1_PSCRL 0x5261 // TIM1 Prescale low 77 | #define _TIM1_ARRH 0x5262 // TIM1 Auto reload high 78 | #define _TIM1_ARRL 0x5263 // TIM1 Auto reload low 79 | #define _TIM1_RCR 0x5264 // TIM1 Repetition counter 80 | #define _TIM1_CCR1H 0x5265 // TIM1 Capture/compare 1 high 81 | #define _TIM1_CCR1L 0x5266 // TIM1 Capture/compare 1 low 82 | #define _TIM1_CCR2H 0x5267 // TIM1 Capture/compare 2 high 83 | #define _TIM1_CCR2L 0x5268 // TIM1 Capture/compare 2 low 84 | #define _TIM1_CCR3H 0x5269 // TIM1 Capture/compare 3 high 85 | #define _TIM1_CCR3L 0x526a // TIM1 Capture/compare 3 low 86 | #define _TIM1_CCR4H 0x526b // TIM1 Capture/compare 4 high 87 | #define _TIM1_CCR4L 0x526c // TIM1 Capture/compare 4 low 88 | #define _TIM1_BKR 0x526d // TIM1 Break register 89 | #define _TIM1_DTR 0x526e // TIM1 Dead time register 90 | #define _TIM1_OISR 0x526f // TIM1 Output idle state 91 | 92 | #define _TIM2_CR1 0x5300 // TIM2 Control 1 93 | #define _TIM2_IER 0x5301 // TIM2 Interrupt enable 94 | #define _TIM2_SR1 0x5302 // TIM2 Status 1 95 | #define _TIM2_SR2 0x5303 // TIM2 Status 2 96 | #define _TIM2_EGR 0x5304 // TIM2 Event generation 97 | #define _TIM2_CCMR1 0x5305 // TIM2 cap/comp mode 1 98 | #define _TIM2_CCMR2 0x5306 // TIM2 cap/comp mode 2 99 | #define _TIM2_CCMR3 0x5307 // TIM2 cap/comp mode 3 100 | #define _TIM2_CCER1 0x5308 // TIM2 cap/comp enable 1 101 | #define _TIM2_CCER2 0x5309 // TIM2 cap/comp enable 2 102 | #define _TIM2_CNTRH 0x530a // TIM2 counter high 103 | #define _TIM2_CNTRL 0x530b // TIM2 counter low 104 | #define _TIM2_PSCR 0x530c // TIM2 prescaler 105 | #define _TIM2_ARRH 0x530d // TIM2 auto-reload high 106 | #define _TIM2_ARRL 0x530e // TIM2 auto-reload low 107 | #define _TIM2_CCR1H 0x530f // TIM2 cap/comp 1 high 108 | #define _TIM2_CCR1L 0x5310 // TIM2 cap/comp 1 low 109 | #define _TIM2_CCR2H 0x5311 // TIM2 cap/comp 2 high 110 | #define _TIM2_CCR2L 0x5312 // TIM2 cap/comp 2 low 111 | #define _TIM2_CCR3H 0x5313 // TIM2 cap/comp 3 high 112 | #define _TIM2_CCR3L 0x5314 // TIM2 cap/comp 3 low 113 | 114 | #define _ADC_DB0RH 0x53e0 // ADC data buffer 0 high 115 | #define _ADC_DB0RL 0x53e1 // ADC data buffer 0 low 116 | 117 | #define _ADC_CSR 0x5400 // ADC control/status 118 | #define _ADC_CR1 0x5401 // ADC config reg 1 119 | #define _ADC_CR2 0x5402 // ADC config reg 2 120 | #define _ADC_CR3 0x5403 // ADC config reg 3 121 | #define _ADC_DRH 0x5404 // ADC data register high 122 | #define _ADC_DRL 0x5405 // ADC data register low 123 | #define _ADC_TDRH 0x5406 // ADC Schmitt trigger disable high 124 | #define _ADC_TDRL 0x5407 // ADC Schmitt trigger disable low 125 | #define _ADC_HTRH 0x5408 // ADC high threshold high 126 | #define _ADC_HTRL 0x5409 // ADC high trheshold low 127 | #define _ADC_LTRH 0x540a // ADC low threshold high 128 | #define _ADC_LTRL 0x540b // ADC low threshold low 129 | #define _ADC_AWSRH 0x540c // ADC watchdog status high 130 | #define _ADC_AWSRL 0x540d // ADC watchdog status low 131 | #define _ADC_AWCRH 0x540e // ADC watchdog control high 132 | #define _ADC_AWCRL 0x540f // ADC watchdog control low 133 | 134 | #define _ITC_SPR1 0x7f70 135 | #define _ITC_SPR2 0x7f71 136 | #define _ITC_SPR3 0x7f72 137 | #define _ITC_SPR4 0x7f73 138 | #define _ITC_SPR5 0x7f74 139 | #define _ITC_SPR6 0x7f75 140 | #define _ITC_SPR7 0x7f76 141 | #define _ITC_SPR8 0x7f77 142 | 143 | -------------------------------------------------------------------------------- /stm8s_003.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for STM8S 003 3 | */ 4 | #ifndef STM8003 5 | #define STM8003 6 | #endif 7 | 8 | #define PTR(addr) *(volatile char *)(addr) 9 | 10 | #define EEPROM PTR(0x4000) 11 | #define EEPROM_SIZE 128 12 | 13 | #define FLASH_BASE PTR(0x8000) 14 | #define FLASH_SIZE 8192 15 | #define FLASH_BLOCK 64 16 | 17 | #define OPT2 PTR(0x4803) // Alternate function remap 18 | #define NOPT2 PTR(0x4804) 19 | 20 | #define UNIQUE_ID PTR(0x4865) // 12-byte unique id 21 | 22 | #define PA_ODR PTR(0x5000) // Port A output latch 23 | #define PA_IDR PTR(0x5001) // Port A input status 24 | #define PA_DDR PTR(0x5002) // Port A data direction 25 | #define PA_CR1 PTR(0x5003) // Port A open drain or pull-ups 26 | #define PA_CR2 PTR(0x5004) // Port A output speed or interrupt 27 | 28 | #define PB_ODR PTR(0x5005) 29 | #define PB_IDR PTR(0x5006) 30 | #define PB_DDR PTR(0x5007) 31 | #define PB_CR1 PTR(0x5008) 32 | #define PB_CR2 PTR(0x5009) 33 | 34 | #define PC_ODR PTR(0x500a) 35 | #define PC_IDR PTR(0x500b) 36 | #define PC_DDR PTR(0x500c) 37 | #define PC_CR1 PTR(0x500d) 38 | #define PC_CR2 PTR(0x500e) 39 | 40 | #define PD_ODR PTR(0x500f) 41 | #define PD_IDR PTR(0x5010) 42 | #define PD_DDR PTR(0x5011) 43 | #define PD_CR1 PTR(0x5012) 44 | #define PD_CR2 PTR(0x5013) 45 | 46 | #define PE_ODR PTR(0x5014) 47 | #define PE_IDR PTR(0x5015) 48 | #define PE_DDR PTR(0x5016) 49 | #define PE_CR1 PTR(0x5017) 50 | #define PE_CR2 PTR(0x5018) 51 | 52 | #define PF_ODR PTR(0x5019) 53 | #define PF_IDR PTR(0x501a) 54 | #define PF_DDR PTR(0x501b) 55 | #define PF_CR1 PTR(0x501c) 56 | #define PF_CR2 PTR(0x501d) 57 | 58 | #define FLASH_CR1 PTR(0x505a) // Flash control 1 59 | #define FLASH_CR2 PTR(0x505b) // Flash control 2 60 | #define FLASH_NCR2 PTR(0x505c) // Flash control 2 complement 61 | #define FLASH_FPR PTR(0x505d) // Flash protection 62 | #define FLASH_NFPR PTR(0x505e) // Flash protection complement 63 | #define FLASH_IAPSR PTR(0x505f) // Flash in-application program status 64 | #define FLASH_PUKR PTR(0x5062) // Flash unprotect 65 | #define FLASH_DUKR PTR(0x5064) // Data EEPROM unprotect 66 | 67 | #define EXTI_CR1 PTR(0x50a0) // External interrupt control 68 | #define EXTI_CR2 PTR(0x50a1) 69 | 70 | #define CLK_ICKR PTR(0x50c0) // Internal clock control 71 | #define CLK_ECKR PTR(0x50c1) // External clock control 72 | #define CLK_CMSR PTR(0x50c3) // Clock master status 73 | #define CLK_SWR PTR(0x50c4) // Clock master switch 74 | #define CLK_SWCR PTR(0x50c5) // Clock switch control 75 | #define CLK_CKDIVR PTR(0x50c6) // Clock divider 76 | #define CLK_PCKENR1 PTR(0x50c7) // Peripheral clock gating #1 77 | #define CLK_CSSR PTR(0x50c8) // Clock security system 78 | #define CLK_CCOR PTR(0x50c9) // Configurable clock control 79 | #define CLK_PCKENR2 PTR(0x50ca) // Peripheral clock gating #2 80 | #define CLK_HSITRIMR PTR(0x50cc) // HSI clock calibration trimming 81 | #define CLK_SWIMCCR PTR(0x50cd) // SWIM clock control 82 | 83 | #define BEEP_CSR PTR(0x50f3) // BEEP control 84 | 85 | #define SPI_CR1 PTR(0x5200) // SPI control #1 86 | #define SPI_CR2 PTR(0x5201) // SPI control #2 87 | #define SPI_ICR PTR(0x5202) // SPI interrupt control 88 | #define SPI_SR PTR(0x5203) // SPI status 89 | #define SPI_DR PTR(0x5204) // SPI data R/W 90 | #define SPI_CRCPR PTR(0x5205) // SPI CRC polynomial 91 | #define SPI_RXCRCR PTR(0x5206) // SPI RX CRC 92 | #define SPI_TXCRCR PTR(0x5207) // SPI TX CRC 93 | 94 | #define SPI_CR1_SPE 0x40 // SPI enable 95 | #define SPI_CR2_BDM 0x80 // Bidirectional (one data wire for read and write) 96 | #define SPI_CR2_BDOE 0x40 // Bidirectional output enable (transmitting) 97 | #define SPI_CR2_RXONLY 0x04 // Enable SPI clock for receiving 98 | #define SPI_ICR_TXIE 0x80 // TX interrupt enable 99 | #define SPI_ICR_RXIE 0x40 // RX interrupt enable 100 | #define SPI_SR_BSY 0x80 // Busy 101 | #define SPI_SR_TXE 0x02 // TX buffer empty 102 | #define SPI_SR_RXNE 0x01 // RX buffer not empty 103 | 104 | 105 | #define UART1_SR PTR(0x5230) // UART1 status 106 | #define UART1_DR PTR(0x5231) // UART1 data 107 | #define UART1_BRR1 PTR(0x5232) // UART1 baud rate #1 108 | #define UART1_BRR2 PTR(0x5233) // UART1 baud rate #2 109 | #define UART1_CR1 PTR(0x5234) // UART1 control #1 110 | #define UART1_CR2 PTR(0x5235) // UART1 control #2 111 | #define UART1_CR3 PTR(0x5236) // UART1 control #3 112 | #define UART1_CR4 PTR(0x5237) // UART1 control #4 113 | #define UART1_CR5 PTR(0x5238) // UART1 control #5 114 | #define UART1_GTR PTR(0x5239) // UART1 guard time 115 | #define UART1_PSCR PTR(0x523a) // UART1 prescaler 116 | 117 | #define SR_OR (1 << 3) 118 | #define SR_TXE (1 << 7) 119 | 120 | #define TIM1_CR1 PTR(0x5250) // TIM1 Control 1 121 | #define TIM1_CR2 PTR(0x5251) // TIM1 Control 2 122 | #define TIM1_SMCR PTR(0x5252) // TIM1 Slave mode control 123 | #define TIM1_ETR PTR(0x5253) // TIM1 External trigger 124 | #define TIM1_IER PTR(0x5254) // TIM1 Interrupt enable 125 | #define TIM1_SR1 PTR(0x5255) // TIM1 status 1 126 | #define TIM1_SR2 PTR(0x5256) // TIM1 status 2 127 | #define TIM1_EGR PTR(0x5257) // TIM1 Event generation 128 | #define TIM1_CCMR1 PTR(0x5258) // TIM1 Capture/compare mode 1 129 | #define TIM1_CCMR2 PTR(0x5259) // TIM1 Capture/compare mode 2 130 | #define TIM1_CCMR3 PTR(0x525a) // TIM1 Capture/compare mode 3 131 | #define TIM1_CCMR4 PTR(0x525b) // TIM1 Capture/compare mode 4 132 | #define TIM1_CCER1 PTR(0x525c) // TIM1 Capture/compare enable 1 133 | #define TIM1_CCER2 PTR(0x525d) // TIM1 Capture/compare enable 2 134 | #define TIM1_CNTRH PTR(0x525e) // TIM1 Counter high 135 | #define TIM1_CNTRL PTR(0x525f) // TIM1 Counter low 136 | #define TIM1_PSCRH PTR(0x5260) // TIM1 Prescale high 137 | #define TIM1_PSCRL PTR(0x5261) // TIM1 Prescale low 138 | #define TIM1_ARRH PTR(0x5262) // TIM1 Auto reload high 139 | #define TIM1_ARRL PTR(0x5263) // TIM1 Auto reload low 140 | #define TIM1_RCR PTR(0x5264) // TIM1 Repetition counter 141 | #define TIM1_CCR1H PTR(0x5265) // TIM1 Capture/compare 1 high 142 | #define TIM1_CCR1L PTR(0x5266) // TIM1 Capture/compare 1 low 143 | #define TIM1_CCR2H PTR(0x5267) // TIM1 Capture/compare 2 high 144 | #define TIM1_CCR2L PTR(0x5268) // TIM1 Capture/compare 2 low 145 | #define TIM1_CCR3H PTR(0x5269) // TIM1 Capture/compare 3 high 146 | #define TIM1_CCR3L PTR(0x526a) // TIM1 Capture/compare 3 low 147 | #define TIM1_CCR4H PTR(0x526b) // TIM1 Capture/compare 4 high 148 | #define TIM1_CCR4L PTR(0x526c) // TIM1 Capture/compare 4 low 149 | #define TIM1_BKR PTR(0x526d) // TIM1 Break register 150 | #define TIM1_DTR PTR(0x526e) // TIM1 Dead time register 151 | #define TIM1_OISR PTR(0x526f) // TIM1 Output idle state 152 | 153 | #define TIM2_CR1 PTR(0x5300) // TIM2 Control 1 154 | #define TIM2_IER PTR(0x5303) // TIM2 Interrupt enable 155 | #define TIM2_SR1 PTR(0x5304) // TIM2 Status 1 156 | #define TIM2_SR2 PTR(0x5305) // TIM2 Status 2 157 | #define TIM2_EGR PTR(0x5306) // TIM2 Event generation 158 | #define TIM2_CCMR1 PTR(0x5307) // TIM2 cap/comp mode 1 159 | #define TIM2_CCMR2 PTR(0x5308) // TIM2 cap/comp mode 2 160 | #define TIM2_CCMR3 PTR(0x5309) // TIM2 cap/comp mode 3 161 | #define TIM2_CCER1 PTR(0x530a) // TIM2 cap/comp enable 1 162 | #define TIM2_CCER2 PTR(0x530b) // TIM2 cap/comp enable 2 163 | #define TIM2_CNTRH PTR(0x530c) // TIM2 counter high 164 | #define TIM2_CNTRL PTR(0x530d) // TIM2 counter low 165 | #define TIM2_PSCR PTR(0x530e) // TIM2 prescaler 166 | #define TIM2_ARRH PTR(0x530f) // TIM2 auto-reload high 167 | #define TIM2_ARRL PTR(0x5310) // TIM2 auto-reload low 168 | #define TIM2_CCR1H PTR(0x5311) // TIM2 cap/comp 1 high 169 | #define TIM2_CCR1L PTR(0x5312) // TIM2 cap/comp 1 low 170 | #define TIM2_CCR2H PTR(0x5313) // TIM2 cap/comp 2 high 171 | #define TIM2_CCR2L PTR(0x5314) // TIM2 cap/comp 2 low 172 | #define TIM2_CCR3H PTR(0x5315) // TIM2 cap/comp 3 high 173 | #define TIM2_CCR3L PTR(0x5316) // TIM2 cap/comp 3 low 174 | 175 | #define TIMx_CEN (1 << 0) // counter enable 176 | #define TIMx_UIE (1 << 0) // update interrupt 177 | #define TIMx_CC1IE (1 << 1) // capture/compare 1 interrupt 178 | #define TIMx_CC2IE (1 << 2) // capture/compare 2 interrupt 179 | #define TIMx_CC3IE (1 << 3) // capture/compare 3 interrupt 180 | #define TIMx_CC1E (1 << 0) // capture 1 enable 181 | #define TIMx_CC1G (1 << 1) // capture/compare 1 generation 182 | #define TIMx_CC1P (1 << 1) // capture/compare 1 polarity 183 | 184 | #define TIM4_CR1 PTR(0x5340) // TIM4 control 1 185 | #define TIM4_IER PTR(0x5343) // TIM4 interrupt enable 186 | #define TIM4_SR PTR(0x5344) // TIM4 status 187 | #define TIM4_EGR PTR(0x5345) // TIM4 event generation 188 | #define TIM4_CNTR PTR(0x5346) // TIM4 counter 189 | #define TIM4_PSCR PTR(0x5347) // TIM4 prescaler 190 | #define TIM4_ARR PTR(0x5348) // TIM4 auto reload 191 | 192 | #define ADC_DB0RH PTR(0x53e0) // ADC data buffer 0 high 193 | #define ADC_DB0RL PTR(0x53e1) // ADC data buffer 0 low 194 | 195 | #define ADC_CSR PTR(0x5400) // ADC control/status 196 | #define ADC_CR1 PTR(0x5401) // ADC config reg 1 197 | #define ADC_CR2 PTR(0x5402) // ADC config reg 2 198 | #define ADC_CR3 PTR(0x5403) // ADC config reg 3 199 | #define ADC_DRH PTR(0x5404) // ADC data register high 200 | #define ADC_DRL PTR(0x5405) // ADC data register low 201 | #define ADC_TDRH PTR(0x5406) // ADC Schmitt trigger disable high 202 | #define ADC_TDRL PTR(0x5407) // ADC Schmitt trigger disable low 203 | #define ADC_HTRH PTR(0x5408) // ADC high threshold high 204 | #define ADC_HTRL PTR(0x5409) // ADC high trheshold low 205 | #define ADC_LTRH PTR(0x540a) // ADC low threshold high 206 | #define ADC_LTRL PTR(0x540b) // ADC low threshold low 207 | #define ADC_AWSRH PTR(0x540c) // ADC watchdog status high 208 | #define ADC_AWSRL PTR(0x540d) // ADC watchdog status low 209 | #define ADC_AWCRH PTR(0x540e) // ADC watchdog control high 210 | #define ADC_AWCRL PTR(0x540f) // ADC watchdog control low 211 | 212 | -------------------------------------------------------------------------------- /stm8s_003.inc: -------------------------------------------------------------------------------- 1 | /* 2 | * STM8 defines for inline assembly. 3 | * Names are preceded with underscore. 4 | */ 5 | 6 | #define _OPT2 0x4803 // Alternate function remap 7 | #define _NOPT2 0x4804 8 | 9 | #define _UNIQUE_ID 0x4865 // 12-byte unique id 10 | 11 | #define _PA_ODR 0x5000 12 | #define _PA_IDR 0x5001 13 | #define _PA_DDR 0x5002 14 | #define _PA_CR1 0x5003 15 | #define _PA_CR2 0x5004 16 | 17 | #define _PB_ODR 0x5005 18 | #define _PB_IDR 0x5006 19 | #define _PB_DDR 0x5007 20 | #define _PB_CR1 0x5008 21 | #define _PB_CR2 0x5009 22 | 23 | #define _PC_ODR 0x500a 24 | #define _PC_IDR 0x500b 25 | #define _PC_DDR 0x500c 26 | #define _PC_CR1 0x500d 27 | #define _PC_CR2 0x500e 28 | 29 | #define _PD_ODR 0x500f 30 | #define _PD_IDR 0x5010 31 | #define _PD_DDR 0x5011 32 | #define _PD_CR1 0x5012 33 | #define _PD_CR2 0x5013 34 | 35 | #define _PE_ODR 0x5014 36 | #define _PE_IDR 0x5015 37 | #define _PE_DDR 0x5016 38 | #define _PE_CR1 0x5017 39 | #define _PE_CR2 0x5018 40 | 41 | #define _PF_ODR 0x5019 42 | #define _PF_IDR 0x501a 43 | #define _PF_DDR 0x501b 44 | #define _PF_CR1 0x501c 45 | #define _PF_CR2 0x501d 46 | 47 | #define _FLASH_CR1 0x505a // Flash control 1 48 | #define _FLASH_CR2 0x505b // Flash control 2 49 | #define _FLASH_NCR2 0x505c // Flash control 2 complement 50 | #define _FLASH_FPR 0x505d // Flash protection 51 | #define _FLASH_NFPR 0x505e // Flash protection complement 52 | #define _FLASH_IAPSR 0x505f // Flash control 1 53 | #define _FLASH_PUKR 0x5062 // Flash in-application program status 54 | #define _FLASH_DUKR 0x5064 // Data EEPROM unprotect 55 | 56 | #define _EXTI_CR1 0x50a0 57 | #define _EXTI_CR2 0x50a1 58 | 59 | #define _SPI_CR1 0x5200 // SPI control #1 60 | #define _SPI_CR2 0x5201 // SPI control #2 61 | #define _SPI_ICR 0x5202 // SPI interrupt control 62 | #define _SPI_SR 0x5203 // SPI status 63 | #define _SPI_DR 0x5204 // SPI data R/W 64 | #define _SPI_CRCPR 0x5205 // SPI CRC polynomial 65 | #define _SPI_RXCRCR 0x5206 // SPI RX CRC 66 | #define _SPI_TXCRCR 0x5207 // SPI TX CRC 67 | 68 | #define _TIM1_CR1 0x5250 // TIM1 Control 1 69 | #define _TIM1_CR2 0x5251 // TIM1 Control 2 70 | #define _TIM1_SMCR 0x5252 // TIM1 Slave mode control 71 | #define _TIM1_ETR 0x5253 // TIM1 External trigger 72 | #define _TIM1_IER 0x5254 // TIM1 Interrupt enable 73 | #define _TIM1_SR1 0x5255 // TIM1 status 1 74 | #define _TIM1_SR2 0x5256 // TIM1 status 2 75 | #define _TIM1_EGR 0x5257 // TIM1 Event generation 76 | #define _TIM1_CCMR1 0x5258 // TIM1 Capture/compare mode 1 77 | #define _TIM1_CCMR2 0x5259 // TIM1 Capture/compare mode 2 78 | #define _TIM1_CCMR3 0x525a // TIM1 Capture/compare mode 3 79 | #define _TIM1_CCMR4 0x525b // TIM1 Capture/compare mode 4 80 | #define _TIM1_CCER1 0x525c // TIM1 Capture/compare enable 1 81 | #define _TIM1_CCER2 0x525d // TIM1 Capture/compare enable 2 82 | #define _TIM1_CNTRH 0x525e // TIM1 Counter high 83 | #define _TIM1_CNTRL 0x525f // TIM1 Counter low 84 | #define _TIM1_PSCRH 0x5260 // TIM1 Prescale high 85 | #define _TIM1_PSCRL 0x5261 // TIM1 Prescale low 86 | #define _TIM1_ARRH 0x5262 // TIM1 Auto reload high 87 | #define _TIM1_ARRL 0x5263 // TIM1 Auto reload low 88 | #define _TIM1_RCR 0x5264 // TIM1 Repetition counter 89 | #define _TIM1_CCR1H 0x5265 // TIM1 Capture/compare 1 high 90 | #define _TIM1_CCR1L 0x5266 // TIM1 Capture/compare 1 low 91 | #define _TIM1_CCR2H 0x5267 // TIM1 Capture/compare 2 high 92 | #define _TIM1_CCR2L 0x5268 // TIM1 Capture/compare 2 low 93 | #define _TIM1_CCR3H 0x5269 // TIM1 Capture/compare 3 high 94 | #define _TIM1_CCR3L 0x526a // TIM1 Capture/compare 3 low 95 | #define _TIM1_CCR4H 0x526b // TIM1 Capture/compare 4 high 96 | #define _TIM1_CCR4L 0x526c // TIM1 Capture/compare 4 low 97 | #define _TIM1_BKR 0x526d // TIM1 Break register 98 | #define _TIM1_DTR 0x526e // TIM1 Dead time register 99 | #define _TIM1_OISR 0x526f // TIM1 Output idle state 100 | 101 | #define _TIM2_CR1 0x5300 // TIM2 Control 1 102 | #define _TIM2_IER 0x5303 // TIM2 Interrupt enable 103 | #define _TIM2_SR1 0x5304 // TIM2 Status 1 104 | #define _TIM2_SR2 0x5305 // TIM2 Status 2 105 | #define _TIM2_EGR 0x5306 // TIM2 Event generation 106 | #define _TIM2_CCMR1 0x5307 // TIM2 cap/comp mode 1 107 | #define _TIM2_CCMR2 0x5308 // TIM2 cap/comp mode 2 108 | #define _TIM2_CCMR3 0x5309 // TIM2 cap/comp mode 3 109 | #define _TIM2_CCER1 0x530a // TIM2 cap/comp enable 1 110 | #define _TIM2_CCER2 0x530b // TIM2 cap/comp enable 2 111 | #define _TIM2_CNTRH 0x530c // TIM2 counter high 112 | #define _TIM2_CNTRL 0x530d // TIM2 counter low 113 | #define _TIM2_PSCR 0x530e // TIM2 prescaler 114 | #define _TIM2_ARRH 0x530f // TIM2 auto-reload high 115 | #define _TIM2_ARRL 0x5310 // TIM2 auto-reload low 116 | #define _TIM2_CCR1H 0x5311 // TIM2 cap/comp 1 high 117 | #define _TIM2_CCR1L 0x5312 // TIM2 cap/comp 1 low 118 | #define _TIM2_CCR2H 0x5313 // TIM2 cap/comp 2 high 119 | #define _TIM2_CCR2L 0x5314 // TIM2 cap/comp 2 low 120 | #define _TIM2_CCR3H 0x5315 // TIM2 cap/comp 3 high 121 | #define _TIM2_CCR3L 0x5316 // TIM2 cap/comp 3 low 122 | 123 | #define _ADC_DB0RH 0x53e0 // ADC data buffer 0 high 124 | #define _ADC_DB0RL 0x53e1 // ADC data buffer 0 low 125 | 126 | #define _ADC_CSR 0x5400 // ADC control/status 127 | #define _ADC_CR1 0x5401 // ADC config reg 1 128 | #define _ADC_CR2 0x5402 // ADC config reg 2 129 | #define _ADC_CR3 0x5403 // ADC config reg 3 130 | #define _ADC_DRH 0x5404 // ADC data register high 131 | #define _ADC_DRL 0x5405 // ADC data register low 132 | #define _ADC_TDRH 0x5406 // ADC Schmitt trigger disable high 133 | #define _ADC_TDRL 0x5407 // ADC Schmitt trigger disable low 134 | #define _ADC_HTRH 0x5408 // ADC high threshold high 135 | #define _ADC_HTRL 0x5409 // ADC high trheshold low 136 | #define _ADC_LTRH 0x540a // ADC low threshold high 137 | #define _ADC_LTRL 0x540b // ADC low threshold low 138 | #define _ADC_AWSRH 0x540c // ADC watchdog status high 139 | #define _ADC_AWSRL 0x540d // ADC watchdog status low 140 | #define _ADC_AWCRH 0x540e // ADC watchdog control high 141 | #define _ADC_AWCRL 0x540f // ADC watchdog control low 142 | 143 | #define _ITC_SPR1 0x7f70 144 | #define _ITC_SPR2 0x7f71 145 | #define _ITC_SPR3 0x7f72 146 | #define _ITC_SPR4 0x7f73 147 | #define _ITC_SPR5 0x7f74 148 | #define _ITC_SPR6 0x7f75 149 | #define _ITC_SPR7 0x7f76 150 | #define _ITC_SPR8 0x7f77 151 | 152 | -------------------------------------------------------------------------------- /stm8s_header.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Choose stm8s_003, stm8s_103, stm8s_105, or stm8s_107 header, 3 | * depending on compile directive. 4 | */ 5 | 6 | #ifdef STM8003 7 | #include "stm8s_003.h" 8 | #include "stm8s_003.inc" 9 | #endif 10 | 11 | #ifdef STM8103 12 | #include "stm8_103.h" 13 | #include "stm8_103.inc" 14 | #endif 15 | 16 | #ifdef STM8105 17 | #include "stm8_105.h" 18 | #include "stm8_105.inc" 19 | #endif 20 | 21 | #ifdef STM8S207 22 | #include "stm8s_207.h" 23 | #endif 24 | 25 | #include "vectors.h" 26 | 27 | /* 28 | * Choose syntax for inline assembly. 29 | */ 30 | #ifdef __SDCC 31 | #define __ASM __asm 32 | #define __ENDASM __endasm; 33 | #else 34 | #define __ASM #asm /* Cosmic syntax */ 35 | #define __ENDASM #endasm 36 | #endif 37 | 38 | /* 39 | * Make sure __SDCCCALL is defined so inline assembly can handle 40 | * all versions of the calling convention version. 41 | */ 42 | #ifndef __SDCCCALL 43 | #define __SDCCCALL 0 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /vectors.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Interrupt numbers and vector addresses 4 | */ 5 | 6 | #define VECTT_RESET 0 /* 0x8000 Reset vector */ 7 | #define VECT_TRAP 0 /* 0x8004 Software interrupt */ 8 | #define IRQ_TLI 0 /* 0x8008 External top level interrupt */ 9 | #define IRQ_AWU 1 /* 0x800c Auto wake up from halt */ 10 | #define IRQ_CLK 2 /* 0x8010 Clock controller */ 11 | #define IRQ_EXTI0 3 /* 0x8014 Port A external interrupts */ 12 | #define IRQ_EXTI1 4 /* 0x8018 PORT B external interrupts */ 13 | #define IRQ_EXTI2 5 /* 0x801c PORT C external interrupts */ 14 | #define IRQ_EXTI3 6 /* 0x8020 PORT D external interrupts */ 15 | #define IRQ_EXTI4 7 /* 0x8024 PORT E external interrupts */ 16 | #define IRQ_CANRX 8 /* 0x8028 beCAN RX */ 17 | #define IRQ_CANTX 9 /* 0x802c beCAN TX */ 18 | #define IRQ_SPI 10 /* 0x8030 End of transfer */ 19 | #define IRQ_TIM1 11 /* 0x8034 TIM1 update/over/underflow/trigger */ 20 | #define IRQ_TIM1C 12 /* 0x8038 TIM1 capture/compare */ 21 | #define IRQ_TIM2 13 /* 0x803c TIM2 update/overflow */ 22 | #define IRQ_TIM2C 14 /* 0x8040 TIM2 capture/compare */ 23 | #define IRQ_TIM3 15 /* 0x8044 TIM3 update/overflow */ 24 | #define IRQ_TIM3C 16 /* 0x8048 TIM3 capture/compare */ 25 | #define IRQ_UART_TX 17 /* 0x804c UART TX complete */ 26 | #define IRQ_UART_RX 18 /* 0x8050 UART RX data full */ 27 | #define IRQ_I2C 19 /* 0x8054 I2C interrupt */ 28 | #define IRQ_UART2_TX 20 /* 0x8058 UART2 TX complete */ 29 | #define IRQ_UART2_RX 21 /* 0x805c UART2 RX data full */ 30 | #define IRQ_ADC1 22 /* 0x8060 ADC1 end of conversion/ analog WD */ 31 | #define IRQ_TIM4 23 /* 0x8064 TIM4 update/overflow */ 32 | #define IRQ_FLASH 24 /* 0x8068 EOP / WR_PG_DIS */ 33 | 34 | --------------------------------------------------------------------------------