Last active
January 6, 2019 13:01
-
-
Save TG9541/7f340dea90538f654eb6faa0f32093ac to your computer and use it in GitHub Desktop.
STM8S buffered UART implementation with support for RS485 flow shared medium
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#require WIPE | |
NVM | |
20 CONSTANT RXLEN | |
VARIABLE rxbuf RXLEN 2- ALLOT | |
VARIABLE rxp \ receive xfer pointer in ISR | |
VARIABLE tstamp \ receive timestamp | |
20 CONSTANT TXLEN | |
VARIABLE txbuf TXLEN 2- ALLOT | |
VARIABLE txp \ transmit xfer pointer in ISR | |
VARIABLE tbp \ transmit buffer pointer | |
RAM WIPE | |
\res MCU: STM8S103 | |
\res export INT_UARTRX INT_UARTTX | |
\res export UART1_SR UART1_DR UART1_CR2 | |
#require RS485DE | |
#require PINDEBUG | |
#require WIPE | |
#require :NVM | |
#require ALIAS | |
#require ]B! | |
#require ]B? | |
5 CONSTANT #RIEN | |
6 CONSTANT #TC | |
6 CONSTANT #TCIEN | |
7 CONSTANT #TXE | |
7 CONSTANT #TIEN | |
NVM | |
\ Start UART TX ISR chain | |
: start-tx ( -- ) | |
RS485tx \ enable TX driver | |
txbuf txp ! \ next char: buffer start | |
[ 1 UART1_CR2 #TIEN ]B! \ start ISR chain (TXE is active) | |
; | |
\ reset TX buffer pointer | |
: txres ( -- ) | |
txbuf tbp ! | |
; | |
\ TX ISR handler | |
:NVM | |
SAVEC | |
\ P2H | |
txp DUP @ ( va a1 ) DUP tbp @ < IF | |
( va a1 ) C@ UART1_DR C! | |
( va ) 1 SWAP +! | |
ELSE | |
( va a1 ) 2DROP | |
[ 0 UART1_CR2 #TIEN ]B! \ spin down ISR chain | |
[ 1 UART1_CR2 #TCIEN ]B! \ next ISR call: transfer complete | |
\ test and clear TC ISR | |
[ UART1_SR #TC ]B? IF | |
\ terminate ISR chain and release bus | |
[ 0 UART1_CR2 #TCIEN ]B! | |
txres RS485rx | |
THEN | |
THEN | |
\ P2L | |
IRET | |
[ OVERT INT_UARTTX ! | |
\ headerless: test for enough free space in txbuf for putting n bytes | |
:NVM ( n -- f ) | |
tbp @ txbuf - + 1- TXLEN < | |
;RAM ALIAS test-tbp | |
NVM | |
\ add c to TX buffer | |
: txc+ ( c -- ) | |
1 test-tbp IF | |
tbp @ C! 1 tbp +! | |
THEN | |
; | |
\ add n to TX buffer | |
: tx+ ( n -- ) | |
2 test-tbp IF | |
tbp @ ! 2 tbp +! | |
THEN | |
; | |
\ RX ISR handler | |
:NVM | |
SAVEC | |
P1H | |
UART1_DR C@ | |
( c ) rxp @ ( c a ) DUP rxbuf - ( c a len ) RXLEN < IF | |
( c a ) SWAP ( a c ) OVER ( a c a ) C! | |
( a ) 1+ rxp ! | |
THEN | |
TIM tstamp ! | |
P1L | |
IRET | |
[ OVERT INT_UARTRX ! | |
\ reset RX buffer and initialize RX ISR handler | |
: rxres ( -- ) | |
rxbuf rxp ! | |
[ 1 UART1_CR2 #RIEN ]B! | |
; | |
\ show contents the RX and TX buffers | |
: bufdump ( -- ) | |
CR ." rxbuf:" | |
rxbuf rxp @ OVER - DUP . DUMP | |
CR ." txbuf:" | |
txbuf tbp @ OVER - DUP . DUMP | |
; | |
WIPE RAM | |
\res export UART1_CR2 UART1_BRR1 | |
#require ]C! | |
#require OSCFREQ | |
#require UART_DIV | |
: BR ( br -- ) | |
OSCFREQ UART_DIV | |
; | |
NVM | |
HERE \ pass table address on at compile time | |
240 BR , 480 BR , 960 BR , 1920 BR , 5760 BR , 11520 BR , 23040 BR , | |
\ initilization of buffered UART handler (call this once) | |
: UARTISR ( n -- ) | |
2* ( BR table ) LITERAL + @ UART1_BRR1 ! | |
[ $0C UART1_CR2 ]C! \ enable TX and RX | |
PINDEBUG | |
RS485DE | |
txres rxres | |
; | |
WIPE RAM | |
\\ Example, run e.g. in SWIMCOM | |
#include UARTISR | |
UARTISR | |
txbuf TXLEN 66 FILL | |
65 txbuf C! | |
10 txbuf TXLEN 1- + C! | |
txlen tbp +! | |
start-tx |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ISRs in Forth are quite capable - 30µs processing time max for the code above. Here is the timing of a 115200 baud loop-back:
A discussion is here.