###################################################################################### TinyBasic fuer STM8S103F3P6 Ein ultraminimalistischer Basic-Interpreter Ausgangsdatei von T. Suzuki STM8S Port und Erweiterungen von R. Seelig ###################################################################################### Im Rahmen eines kleinen privaten "Wettbewerbs" ging es darum, wie billig der billigste BASIC-Computer ausfallen kann. Vordergruendig war dieses durch die extrem preiswerten (billigen) Teile aus China initiiert worden. Da bei solchen Dingen der Spieltrieb und der Ehrgeiz geweckt wird habe ich mich an das Werk gemacht und das hier ist das Resultat. Den preiswertesten Microcontroller den ich gefunden (und sogar verfuegbar) hatte war im Jahr 2016 ein STM8S103F3P6. Stand 2023 waere ein STM32F030f4 bei sehr deutlich besseren Leistungsdaten preiswerter. Hier jedoch die Version fuer STM8S103. ###################################################################################### Serielle Schnittstelle / UART ###################################################################################### Um ein Basic-Programm eingeben zu koennen bedarf es einer Eingabemoeglichkeit und hier- fuer verwende ich standardmaessig den CH340G Dieser Chip ist eine USB2RS232 Bruecke und leistet mir unter Linux super gute Dienste. Zum Flashen des Controllers benoetigt man einen ST-LINK v2. Ein Chinaclone-Stick ist hier von Vorteil, weil diese ausser einem STM32 auch einen STM8 flashen koennen. ###################################################################################### Der Schaltplan ###################################################################################### +5V 3.3V 3.3V 3.3V ST-Link ^ ^ ^ ^ o o o o 3.3V 47u | 100n | | 100n | | N | S | +----||---+ +----||---| | +----||---+ | R | W | | | | | +-+ | | | S | I | | | --- | 2,2k | | --- | | T | M | -- | | | | +--------------|-------+ | --- | | +-+ | | | +--------+ | +---------------------+ | | +------------------------------------------------------------+ | U +5V | --+ | 16 | TxD | | | 9 18 | | S D+ | ----------| 6 2 |--------|----|--| 3 RxD Vdd PD1 | | B D- | ----------| 5 CH340G | RxD | | | | | GND | --+ | 3 |--------|----|--| 2 TxD PA1 5 |---+ +--------+ | +---| 4 | 100n | | | STM8 S103F3P6 | | | | | 13 |---||---+----+--| 4 NRST | | | | | 7 8 | DTR | | | | | | +---------------------+ | | GND VCAP PA3 PB4 PB5 PC3 PC4 PC5 PC6 PC7 PD3 PD4 | | | | 100n | | | | | 7 8 10 12 11 13 14 15 16 17 20 1 | | | === +--|#|--+ | \ +------------------------------------------------------------+ | | | | | | \ | | | | | | | | | | | | | | | | 12MHz | | | | | 1u | | | | | | | | | | | | | === === | | | === | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | --- --- --- --- --- --- --- --- | | | | | | | | | | | o o o o o o o o o o o +----------+ io0 io1 io2 io3 io4 io5 io6 io7 io8 io9 Autorun | AMS 1117 | 5V o----+----| 3.3 |----+----> 3.3V | +----------+ | | | === === | | --- --- ###################################################################################### Die Basicinterpreter-Firmware ###################################################################################### Die Firmware ist in der gepackten ZIP-Datei enthalten. Es benoetigt ein Linux um dieses zu uebersetzen. Der hierfuer verwendete Compiler fuer die Firmware ist SDCC in der Version 3.50. Er kann gedownloaded werden unter: https://sourceforge.net/projects/sdcc/files/sdcc-linux-x86 Hier die Version 3.50 waehlen (Vertraeglichkeiten mit neueren Versionen sind nicht getestet). Den Installationsanweisungen auf Sourceforge folgen um den Compiler zu installieren. Ein Verzeichnis der Wahl erstellen, bpsw.: cd ~ mkdir stm8projects und das Firmwarepackage in dieses Verzeichnis entpacken Hier entstehen dann folgende Verzeichnissstruktur: basict ---------- Makefile sendbas19200 sendbas19200.c compilesendbas readme.txt schaltplan.txt tbasic.c array.bas ascii.bas blink.bas fakul.bas lauflicht.bas include --------- stm8s.h stm8_init.h stm8_gpio.h stm8_systimer.h src ------------- stm8_systimer.c stm8_init serial_demo ----- C-Demoprogramm fuer die serielle Schnittstelle blinky ----- C-Demoprogramm blinkende LED toolsource --+-- ch340reset_b => Tool zum Zuruecksetzen des USB2UART Chip | +-- picocom => Terminalprogramm fuer die Konsole zur | Bedienung des Basicinterpreters | +-- readihx => Tool zum Ermitteln des Speicherbedarfs | einer Intel-Hex Datei | +-- stm8_bootflashv2 => Hostprogramm, das ein Programm an den | STM8r sendet, wenn in diesem ein | Bootloader installiert ist | +-- stm8flash => Hostprogramm zum Flashen des STM8 | ueber einen Chinaclone ST-Link | +-- sendbas => einfaches Toolprogramm, um eine Basic- textdatei an den Interpreter zu senden makefile.mk stm8unlock stm8unlock.bin stm8flash stm8_bootflash2 st8readihx picocom Leider sind bei Auslieferung der STM8S103 Boards diese "gelockt", so dass dieses aufgehoben werden muss. Das geschieht jedoch relativ einfach in Verbindung mit dem ST-Link v2. Verbinden Sie die 4 Leitungen des Boards mit dem ST-Link. Die Leitungen sind bezeichnet mit SWIM, RST, GND, 3.3V und rufen Sie das Programm stm8unlock auf: ./stm8unlock Der Lock wurde somit aufgehoben. Wechseln sie in das Verzeichnis basict cd basict und fuehren Sie das Makefile mittels Make aus: make Ist der SDCC korrekt installiert wird nun ein Binarie erzeugt, dieses kann mittels make flash in den Controller uebertragen werden. ###################################################################################### Bootloader Alternative ###################################################################################### Um den STM8 zu flashen (nicht ein Basicprogramm) kann vor der Installation der Interpreterfirmware ein Bootloader installiert werden. Danach kann der STM8 alleine ueber die USB2UART-Bridge geflasht werden (bspw. wenn man den Controller anstelle des Interpreters mit einer anderen Firmware programmieren moechte. Hierzu benoetigt man einmalig den ST-Link um den Bootloader zu flashen. Hierzu den ST-Link an die Anschluesse +Vcc (3.3V), GND, NRST und SWIM anschliessen und in das Verzeichnis ./toolsource/stm8_bootflashv2 wechseln. Dort ist ein make f103 einzugeben um den Bootloader zu erstellen. Ein make flash103 installiert den Bootloader. Fortan ist der STM8 ueber diesen programmierbar und ein ST-Link wird dann nicht mehr benoetigt. Hierist anzumerken, dass der Bootloader selbst 449 Bytes benoetigt, so dass ein Anwenderprogramm "nur" noch 7743 anstelle von 8192 Bytes gross sein darf. Soll ueber den Bootloader geflasht werden ist in den Makefiles die zu verwendende Auswahl des Programmers anzugeben: # FLASHERPROG Auswahl fuer STM8: # 0 : stm8flash (ueber ST-Link Adapter) 1 : stm8_bootflash (Bootloader) # 2 : stm8_bootflash (Bootloader mit Statusanzeige) PROGPORT = /dev/ttyUSB0 CH340RESET = 0 FLASHERPROG = 2 Der Basic-Interpreter ist nun betriebsbereit und an sich wird nun der ST-Link nicht mehr benoetigt und kann, wenn die USB-Leitung angeschlossen ist, abgezogen werden. Oeffnen sie ein weiteres Konsolenfenster und wechseln sie in das Verzeichnis stm8projects/basict Starten Sie das Terminal picocom mittels ../picocom -b 57600 /dev/ttyUSB0 Sollten sie mehrere USB2RS232 - Bruecken installiert haben, kann der Name ttyUSB0 abweichen, abhaengig davon, wieviele Adapter gerade aktiv sind (bspw. koennte es auch ttyUSB1 heissen). Picocom ist ein superkleines und sehr spartanisches serielles Terminalprogramm, es kann beendet werden mit der Tastenkombination (alle gleichzeitig druecken): STRG A X Wenn sie die Resettaste des STM8S103 Boards druecken, meldet sich der Basic-Interpreter mit STM8S103F3P6 -- TBasic v1.01 -- 19200Bd 8n1 511 Bytes free OK > Sie koennen nun hier ein Basicprogramm eingeben, oder oeffnen sie ein weiteres Terminal und wechseln in das Verzeichnis stm8projects/tbasic Hier koennen sie mittels sendbas19200 eine Textdatei, die ein lauffaehiges Basic-Programm darstellt ueber die serielle Schnittstelle an den Basic-Interpreter uebermitteln: ./sendbas19200 lauflicht.bas /dev/ttyUSB0 WICHTIG: Der Basicinterpreter MUSS in einem Terminalfenster laufen. sendbas19200 funktioniert so, als ob Sie den Text im Terminal mittels Tastatur eingegeben haetten ###################################################################################### Der Basic-Interpreter ###################################################################################### Der Interpreter ist aufgrund der minimalen Hardware extrem "abgespeckt". Jeder Programmzeile muss eine Zeilennummer vorangestellt werden. Variablename bestehen aus einem einzelnen Buchstaben und koennen von a..z reichen. Ein laufendes Programm kann mit der ESC-Taste abgebrochen werden. Es stehen folgende Programmbefehle zur Verfuegung: ----------------------- PRINT ----------------------- Gibt Texte, Variableninhalte oder numerische Zahlen aus 10 print "Text" 20 print "Variable", a Wird dem Print-Befehl ein Komma nachgestellt, erfolgt kein Zeilenvorschub: 30 print "Zahl: ", 40 print 4*3 ----------------------- INPUT ----------------------- Eine Variable ueber die serielle Schnittstelle einlesen 10 print "Zahl eingeben ", 20 input x 30 print "Die Zahl war: ",x ----------------------- GOSUB / RETURN ----------------------- Ein Unterprogramm aufrufen, hier ein Blinkprogramm mit einer Warteschleife als Unterprogramm ab Zeilennumme 200 10 out(0)= 0 20 gosub 200 30 out(0)= 1 40 gosub 200 50 goto 10 200 rem ########### 210 rem delay 220 rem ########### 230 for x= 1 to 8000 240 next x 250 return ----------------------- OUT ----------------------- Einem Ausgangsportpin einen Wert zuweisen out(pinnummer)= 0 setzt den Portpin auf logsich 0, = 1 setzt den Portpin auf logisch 1 Das Pinmapping der Portpins 0 .... PA3 1 .... PB4 2 .... PB5 3 .... PC3 4 .... PC4 5 .... PC5 6 .... PC6 7 .... PC7 8 .... PD3 9 .... PD4 Das Beispiel in GOSUB / RETURN schaltet den Portpin PA3 abwechselnd ein und aus. ----------------------- IN ----------------------- Einen Portpin einlesen 10 i= in(3) 20 if i=0 goto 10 30 print "Pin ist 1" 40 goto 10 ----------------------- IF ----------------------- Bedingte Programmverzweigung Der IF - Befehl ist in seiner Funktion eingeschraenkt, er kennt nicht wie bei BASIC ueblich ein THEN und ein ELSE, er kann lediglich bei erfuellter Bedingung zu einer anderen Programmzeile verweisen. Befehlsbedingungen sind groesser, kleiner, gleich (es gibt kein ungleich) ----------------------- FOR / NEXT ----------------------- Programmschleife Fuehrt Anweisungen wiederholt aus: 10 for z= 1 to 10 20 print z," * ",z," = ",z*z 30 next z ----------------------- ABS ----------------------- Gebe den Absolutwert einer Zahl aus i= abs(-12) print i Die Ausgabe ist 12 ----------------------- FUNC ----------------------- fuehrt einen "Systemaufruf" durch. Aufgrund der begrenzten Resourcen sind derzeit nur zwei unterschiedliche Systemaufrufe vorhanden func Nummer, Argument Systemfunktion 1 : gebe Asciizeichen aus Argument: auszugebendes Ascii-Zeichen 2 : gibt ein Byte auf den IO-Pins 0..7 aus Arbument: auszugebendes Zeichen Gibt die Buchstaben A..Z aus 10 for a= 65 to 90 20 func 1,a 30 next a Gibt 10101010 auf den IO-Pins aus 10 func 2,170 ----------------------- Array ----------------------- TBasic verfuegt ueber ein einzelnes Array das ueber das @ - Zeichen an- gesprochen werden kann. Dieses Array kann max. 32 Werte aufnehmen @(index)= Wert 10 print "Geben Sie 4 Zahlen ein" 20 for i= 1 to 4 30 print "Zahl ",i,": " 40 input z 50 @(i)= z 60 next i 70 print "Die Zahlen waren:" 80 for i= 1 to 4 90 z= @(i) 100 print "Zahl ",i,": ",z 110 next i ----------------------- SIZE ----------------------- gibt den freien Verfuegbaren Speicher zurueck print size() ---------------------------------------------- Interpreterbefehlseingaben ---------------------------------------------- LIST : listet das aktuelle Programm auf SAVE : speichert das aktuelle Programm im internen EEPROM des Microcontrollers LOAD : laedt das aktuelle Programm aus dem internen EEPROM RUN : startet das Programm im Speicher NEW : loescht den Speicher ---------------------------------------------- Autoload and Run - Funktion ---------------------------------------------- Es ist moeglich den Interpreter so zu betreiben, dass ein im EEPROM gespeichertes Programm nach anlegen der Betriebsspannung automatisch geladen und gestartet wird. Der "Autorun" Pin ist PA1 (Pin 5 bei einem TSSOP20 Gehauese). Ist dieser Pin beim Anlegen der Betriebsspannung mit GND verbunden, wird ein gespeichertes Programm automatisch geladen und gestartet. Im Terminalmodus des Interpreters kann dieses Programm mittels der ESC-Taste ge- stoppt werden. ############################################################################################## Anhang ############################################################################################## I/O Mapping fuer STM8S103F3 ------------ (PD4) I/O 9 | 1 20 | I/O 8 (PD3) UART_TX | 2 19 | (PD2) UART_RX | 3 18 | SWIM NRST | 4 17 | I/O 7 (PC7) (PA1) Autorun | 5 16 | I/O 6 (PC6) | 6 15 | I/O 5 (PC5) Vss (GND) | 7 14 | I/O 4 (PC4) VCAP (*1) | 8 13 | I/O 3 (PC3) Vdd (+Ub) | 9 12 | I/O 1 (PB4) (PA3) I/O 0 | 10 11 | I/O 2 (PB5) ------------ *1 : Ist mit min. 1uF gegen GND zu verschalten ----------------------------------------------------------------------------------------------- Demo-Programme ----------------------------------------------------------------------------------------------- ############################################################################################## Knight-Rider Lauflicht Hier muten die Ausgabe auf den I/O Port etwas "merkwuerdig" an. Dieses liegt zum einen daran, dass TBasic keine hexadezimalen und binaere Zahleneingaben verarbeiten kann. Die Zahl 255 be- deutet, dass in einem Byte alle Bits gesetzt sind: 255d = 0xff = 11111111b In diesem Programm sind die Leuchtdioden so angeschlossen, dass sie bei einer 0 leuchten (Kathode zum Portpin, Anode ueber einen Widerstand nach +Vcc). Diese invertierte Logik hat seinen Sinn darin, dass die Portpins PB4 und PB5 des STM8 Open-Drain Anschluesse sind und deshalb nicht in der Lage sind, bei einer 1 den von einer LED benoetigten Strom zu treiben. Die Rechenoperation 255-Ausgabemuster invertiert hierbei das auszugebende binaere Muster. Eine 1 am I/O-Pin 8 laesst das Lauflicht langsam, eine 0 schnell laufen 10 b= 1 20 c= 255-b 30 func 2,c 40 gosub 140 50 b= b*2 60 if b= 128 goto 80 70 goto 20 80 c= 255-b 90 func 2,c 100 gosub 150 110 b= b / 2 120 if b= 1 goto 20 130 goto 80 140 rem -- DELAY -- 150 d= in(8) 160 if d= 1 goto 200 170 for x= 1 to 3000 180 next x 190 return 200 for x= 1 to 10000 210 next x 220 return ############################################################################################## Ascii-Tabelle 10 print "Die Ascii Tabelle" 20 print 30 b= 0 40 for a= 32 to 127 50 if a> 99 goto 70 60 func 1,32 70 print a,": ", 80 func 1,a 90 print " ", 100 b= b+1 110 if b< 10 goto 150 120 func 1,10 130 func 1,13 140 b= 0 150 next a 160 print 170 stop ############################################################################################## Fakultaetberechnung 10 rem ################## 20 rem Fakultaet 30 rem ################## 40 input "Eingabe Fakultaet : " x 50 f=1 60 for z=1 to x 70 f= f*z 80 next z 90 print "Fakultaet ",x," = ",f 100 stop ############################################################################################## Blinkprogramm Eine 1 am I/O-Pin 8 laesst eine Leuchtdiode schneller, eine 0 langsamer blinken 10 out(0)= 0 20 gosub 200 30 out(0)= 1 40 gosub 200 50 goto 10 200 rem ########### 210 rem delay 220 rem ########### 230 a= in(8) 240 if a=1 goto 280 250 for x= 1 to 32000 260 next x 270 return 280 for x= 1 to 8000 290 next x 300 return