###################################################################################### TinyBasic fuer STM32F030F4P6 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 ist ein STM32F030f4 bei sehr deutlich besseren Leistungsdaten preiswerter. Hier LAO die Version fuer STM32f030 F4P6. ###################################################################################### Der Schaltplan ###################################################################################### +5V 3.3V 3.3V 3.3V 3.3V 3.3V ^ ^ ^ ^ ^ ^ 47u | 100n | | | | | +----||---+ +----||---| | | 100n | | | | | | +-+ | +---||---+----+ +-+ | | --- | 2,2k | | | | | | | | -- | | | | \ Boot0 --- | | | | | | +-+ \ | | +-+ +--------+ | +---------------------+ | | +----------------------------------------------------------+ | | U +5V | --+ | 16 | TxD | | | 16 5 | | | S D+ | ----------| 6 2 |-------|----|---| 18 RxD PA10 Vdd Vdda | | | B D- | ----------| 5 | RxD | | | | | | GND | --+ | 3 |-------|----|---| 17 TxD PA9 | | +--------+ | +---| 4 CH340G | | | | | | | | | | +----|---| 4 NRST STM32F030F4P6 - TSSOP20 PF0 2 |----+ | | | | | | | | | | | | | | +---| 1 Boot0 | | | | | 7 8 | | | | | | | | +---------------------+ | | | GND PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PB1 PA13 PA14 PF1 | | | | 100n | | | | | | 15 6 7 8 9 10 11 12 13 14 19 20 3 | | | === +--|#|--+ | \ +-+ +----------------------------------------------------------+ | | | | | | rst \ | | | | | | | | | | | | | | | | | | | 12MHz | | | | | 4,7k | | | | | | | | | | | | | | | | === === | | +-+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | --- --- --- --- --- --- --- --- | | | | | | | | | | | | | o o o o o o o o o o o o o +----------+ io0 io1 io2 io3 io4 io5 io6 io7 io8 io9 io10 io11 Autorun | AMS 1117 | ADC 5V o----+----| 3.3 |----+----> 3.3V | +----------+ | | | === === | | --- --- ###################################################################################### Vorbereitungen ###################################################################################### Ein Verzeichnis der Wahl erstellen, bpsw.: cd ~ mkdir stm32f0projects und das Firmwarepackage in dieses Verzeichnis entpacken. Hier entsteht dann ein Ornder names basict2_ucnet der folgende Verzeichnissstruktur aufweist: bin ------------- ch340reset picocom sendbas stm32flash include --------- sysf030_init.h uart.h lib ------------- die LIBOPENCM3 Bibliothek src ------------- sysf030_init.c uart.c toolsource --+-- ch340reset_b => Tool zum Zuruecksetzen des USB2UART Chip | +-- picocom => Terminalprogramm fuer die Konsole zur | ueber einen Chinaclone ST-Link | +-- sendbas => einfaches Toolprogramm, um eine Basic- | textdatei an den Interpreter zu senden | +-- stm32flash => Flasher / Uploadprogramm fuer STM32F Mikrocontroller ueber serielle Schnitt- stelle basict ---------- Makefile adc.bas array.bas ascii.bas blink.bas fakul.bas lauflicht.bas makefile.mk => funktionaler Teil des Makefile readme.txt schaltplan.txt tbasic.c tbasic_ports.h tbasic.bin tbasic.elf array.bas ascii.bas blink.bas fakul.bas lauflicht.bas ###################################################################################### 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. Da der STM32F030 ueber einen eingebauten seriellen Bootloader verfuegt, wird der Mikrocontroller ebenfalls ueber diese USB2RS232 Bruecke geflasht. Leider hat der Linuxtreiber fuer diesen Chip wohl ein Problem mit dem Paritycheck und deshalb kann es sein, dass ein gepatchter Treiber fuer CH340 installiert werden muss. Dieser Treiber befindet sich im Ordner: ./toolsource/stm32flash/ch340_driverpatch Dieser Patch muss fuer Ihr Linux-System compiliert werden. Hierzu wechseln Sie zuerst in dieses Verzeichnis: cd ./toolsource/stm32flash/ch340_driverpatch und melden sich als Superuser an: su Nach der Eingabe von su wird das Passwort fuer den Administrator abgefragt. Danach mittels make den Treiber uebersetzen und mit cp ./ch341.ko /lib/modules/$(uname -r)/kernel/drivers/usb/serial/ in das System kopieren. Starten Sie danach den Rechner neu, ein korrigierter Treiber fuer die CH340G USB2RS232 Bruecke ist somit verfuegbar. ###################################################################################### Compilieren und Flashen der Basicinterpreter-Firmware ###################################################################################### Wechseln Sie in das Verzeichnis ./basict2_ucnet und compilieren sie die Firmware mit make Hier wird ein im System installierter arm-none-eabi-gcc Compiler vorausgesetzt. Die Firmware bedient sich NICHT der HAL der ST sondern verwendet die freie LIBOPENCM3 Bibliothek. Diese ist im Verzeichnis ./lib bereits enthalten und Bedarf keiner Aenderung. Um den Mikrocontroller zu flashen muss dieser in den Bootloadermodus versetzt werden. Dieses wird bewerkstelligt indem: - zuerst die Taste Boot0 gedrueckt UND gehalten wird - die Reset-Taste gedrueckt und wieder losgelassen wird - die Boot0 Taste wieder losgelassen wird Der Bootloader erwartet nun, die Firmware zu installieren. Eeben sie ein: make flash Die Firmware ist installiert. Mit ./bin/picocom starten sie ein kleines Terminalprogramm mit dem Sie im Interpreter programmieren und diesen kontrollieren koennen. Druecken Sie nach dem Start des Terminalprogramms die Resettaste und es erscheint die Betriebsmeldung des Interpreters. Starten Sie das Terminal picocom mittels ../picocom -b 115200 /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 bei geoeffnetem Terminal druecken, meldet sich der Basic-Interpreter mit: #### TinyBasic for STM32F030 F4P6 #### CPU running at 48MHz 2047 Bytes free Baudrate 115200 8N1 (c) 2016, 2020, 2023 R. Seelig OK > Sie koennen nun hier ein Basicprogramm eingeben, oder oeffnen sie ein weiteres Terminal und wechseln dort in das Verzeichnis basict2_ucnet Hier koennen sie mittels sendbas eine Textdatei, die ein lauffaehiges Basic-Programm darstellt ueber die serielle Schnittstelle an den Basic-Interpreter im anderen Konsolen- fenster uebermitteln: ./bin/sendbas lauflicht.bas /dev/ttyUSB0 WICHTIG: Der Basicinterpreter MUSS in einem Terminalfenster laufen. sendbas 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 ----------------------- IN / OUT ----------------------- Einem Ausgangsportpin einen Wert zuweisen oder von diesem lesen out(pinnummer)= 0 setzt den Portpin auf logsich 0, = 1 setzt den Portpin auf logisch 1 variable= in(pinnummer) Das Pinmapping der Portpins 0 .... PA0 1 .... PA1 2 .... PA2 3 .... PA3 4 .... PA4 5 .... PA5 6 .... PA6 7 .... PA7 8 .... PB1 9 .... PA13 10 .... PA14 11 .... PF1 Zeigt den logischen Zustand von Portpin 8 auf Portpin 0 an. 10 i= in(8) 20 out(0)= i 30 goto 10 Hinweis: Portpin 8 (PB1) kann auch als analoger Eingang genutzt werden ----------------------- ADC ----------------------- Zeigt den analogen Spannungswert an Portpin 8 (PB1) als 8-Bit Binaerwert auf den Portpins 0..7 (PA0 .. PA7) an. Hinweis: Der ADC des STM32F030 hat eine Aufloesung von 12 Bit. Aus diesem Grund muss dieser fuer eine Ausgabe mittels byteout auf 8 Bit reduziert werden. 10 v= adc() / 16 20 byteout(v) 30 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 nur eine einzelne Anweisung ausfuehren (bspw. ein goto Zeilennummer) Befehlsbedingungen sind groesser, kleiner, gleich (es gibt kein ungleich) 10 i= 7 20 if i>10 print "I ist groesser als 10" 30 if i<10 print "I ist kleiner als 10" 40 if i=10 print "I ist 10" 50 stop ----------------------- FOR / NEXT ----------------------- Programmschleife Fuehrt Anweisungen wiederholt aus (hier die Ausgabe von Quadratzahlen) 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 ----------------------- DELAY ----------------------- Verzoegert die Programmausfuehrung um die angegebene Anzahl Millisekunden 10 out(0)= 0 20 delay (500) 30 out(0)= 1 40 delay (500) 50 goto 10 ----------------------- 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 Gibt die Buchstaben A..Z aus 10 for a= 65 to 90 20 func 1,a 30 next a ----------------------- 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 ----------------------- STOP ----------------------- haelt das Programm an ----------------------- 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 Flash gespeichertes Programm nach anlegen der Betriebsspannung automatisch geladen und gestartet wird. Der "Autorun" Pin ist PF0 (Pin 2 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 STM32F030 ------------ Boot0 | 1 20 | I/O 10 (PA14) (PF0) Autorun | 2 19 | I/O 9 (PA13) (PF1) I/O 11 | 3 18 | RxD (PA10) NRST | 4 17 | TxD (PA9) Vdda | 5 16 | Vdd (PA0) I/O 0 | 6 15 | GND (PA1) I/O 1 | 7 14 | I/O 8 (PB1) (PA2) I/O 2 | 8 13 | I/O 7 (PA7) (PA3) I/O 3 | 9 12 | I/O 6 (PA6) (PA4) I/O 4 | 10 11 | I/O 5 (PA5) ------------ ----------------------------------------------------------------------------------------------- Demo-Programme ----------------------------------------------------------------------------------------------- ############################################################################################## Knight-Rider Lauflicht Hier mutet 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 Eine 1 am I/O-Pin 11 laesst das Lauflicht langsam, eine 0 schnell laufen 10 b= 1 20 byteout (b) 30 gosub 120 40 b= b*2 50 if b= 128 goto 70 60 goto 20 70 byteout (b) 80 gosub 120 90 b= b / 2 100 if b= 1 goto 20 110 goto 70 120 rem -- SPEED -- 130 d= in(11) 140 if d= 1 goto 170 150 delay (50) 160 return 170 delay (500) 180 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 10 out(0)= 0 20 delay(200) 30 out(0)= 1 40 delay(200) 50 goto 10 ############################################################################################## Demoprogramm fuer den Analog/Digitalwandler liest die Spannung an I/O Pin 8 ein und zeigt diese als 8-Bit Wert auf den Portpins 0..7 digital an. Eine Umrechnung in einen Spannungswert von 0 .. 3.3V erfolgt und werden ueber die serielle Schnittstelle als Spannungswert angezeigt (3.3V werden als 3.26V angezeigt werden). 10 v= adc() 20 byteout (v/16) 30 print "ADC-Digits: ", v, " ", 40 rem ## Spannungsanzeige ## 50 a=(v*8) 60 b= (a/10000) 70 print "U= ",b,".", 80 print (a-(b*10000))/100," V ", 90 func 1,13 100 rem ## Speed ## 110 for i= 1 to 10 120 delay (20) 130 next i 140 goto 10 ############################################################################################## Demoprogramm fuer das Array 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