Bascom(P) unter Linux
Überblick
Ich nutze Linux seit 1998, hatte mich inzwischen weitgehend von Windows
gelöst und nur noch auf meinem Dienst-Notebook ein "Not-Windows". Als
ich 2007 begann, mich für die Mikrocontrollerprogrammierung unter
Bascom zu interessieren, war das ein lästiger Rückschritt, der häufiges
"Umbooten nach Windows" erforderte.
Man kann zwar prinzipiell Windows-Programme mit "Wine" unter
Linux ausführen, aber viele laufen halt doch nicht anständig und
erfordern Abstriche bei der Funktionalität.
"Wine" stellt ein rekursives Akronym dar, und der vollständige
Name "Wine Is Not an Emulator" erklärt, warum manche kleinere Programme
gut funktionieren, einige viel nachgefragte mittelprächtig (z.B. ältere
Microsoft-Office-Versionen) und manche "Exoten" eher schlecht bis gar
nicht:
Wine ist kein Emulator wie Vmware, VirtualBox, QEmu oder
DosBox, die versuchen, eine PC-Hardware mehr oder weniger vollständig
zu emulieren und einem Betriebssystem wie Windows einen PC vorzugaukeln, sondern Wine ist lediglich eine Zwischenschicht, die einem einzelnen Windows-Programm
vorgaukelt, auf einem Windows-Betriebssystem zu laufen. Wine fängt also
Betriebssystemaufrufe des Windows-Programmes ab und setzt sie in
Linux-Betriebssystemaufrufe um und umgekehrt.
Dies hat Vor- und Nachteile:
Der Vorteil ist, dass die Windows-Programme nicht allzusehr
ausgebremst werden, da ihr Binärcode vom verwendeten Intel- oder
AMD-Prozessor direkt "verstanden" wird; ein Emulator müsste
Maschinenbefehl für Maschinenbefehl komplett übersetzen, Wine kann das
meiste direkt an den Hardware-Prozessor "durchreichen".
Der Nachteil ist, dass die Windows-Umgebung ein "moving target"
ist, ständig kommen neue DLLs und harwarenahe Betriebssystemaufrufe
hinzu, die verzögert oder gar nicht in "Wine" aufgenommen und ggf.
nicht verstanden werden. Ein Emulator hat es da einfacher; er stellt
eine (im allgemeinen veraltete) virtuelle Hardware zur Verfügung, und
das Gast-Betriebssystem sowie die Gast-Anwendungen haben damit
zurechtzukommen.
Ein weiterer Nachteil ist, dass Wine an die Intel-Architektur
gebunden ist; Wine läuft also leider nicht auf ARM-Boards wie z.B. dem
RaspBerry Pi.
Bascom ist aus Wine-Sicht offenbar ein Exot. Die Demo-Version
lässt sich problemlos installieren (mit der Vollversion gibt es
möglicherweise Probleme mit dem Online-Updater, das habe ich aber nicht
ausprobiert), aber wenn man es aus einem xterm startet, erscheinen
haufenweise Fehlermeldungen auf der Konsole, weil Wine allerlei
Betriebssystemaufrufe nicht nach Linux übersetzen kann.
Je nach Wine-Version kann es passieren, dass Bascom komplett
"abschmiert", wie es so schön drastisch heißt, oder nach einer Weile
zwar doch noch startet, aber dann auch im Leerlauf einen Prozessorkern
zu 100% auslastet und sich im Antwortverhalten recht "zäh" anfühlt.
Früher war Wine auch berüchtigt für Regressionen: nach einem
Update der Wine-Version kam es manchmal vor, dass etwas nicht mehr
funktionierte, das vorher keine Probleme machte.
Es gibt aber einen Ausweg aus dem Dilemma: neben dem grafikbasierten bascavr.exe gibt es das unscheinbare Kommandozeilenprogramm bascomp.exe, das die Kernaufgabe, nämlich die Übersetzung eines *.bas-Files in ein *.bin- oder *.hex-File, genauso gut erledigt.
Bascomp.exe läuft problemlos unter Wine, da es wohl nur sehr
grundlegende Windows-Systemaufrufe tätigt. Ohne die grafische
Programmierumgebung (IDE) wird jedoch das Schreiben eines
Bascom-Programmes und das Flashen sehr unkomfortabel. Unter Linux gibt
es zwar allerlei Editoren und IDEs, aber sie kennen den Bascom-Dialekt
nicht und können daher kein brauchbares "syntax highlighting", also das
"Einfärben" der Bascom-Befehle, das den Quellcode erst übersichtlich
macht.
Ich hatte daher zunächst versucht, mir ein paar Hilfsmittel zu
basteln. Unter Linux gibt es einige Editoren, denen man eigene
Syntax-Files "unterschieben" kann, ohne das Editor-Programm neu
kompilieren zu müssen. Außerdem entstand ein kleines Skript, das das
Kompilieren und Flashen vereinfacht (also den Aufruf von
wine/bascomp.exe und von avrdude automatisiert).
Mittlerweile nutze ich die recht kompakte Linux-IDE "Geany",
die - einmal eingerichtet - nicht mehr viel gegenüber dem Original
vermissen lässt.
Bascom(p) installieren
Zunächst ist natürlich Wine mit dem distributionseigenen Paketmanager zu installieren. Dann lädt man die
Bascom-Demo
herunter und installiert sie unter Wine mit "wine setup.exe". Das gesamte virtuelle Wine-Filesystem liegt ja im versteckten Ordner .wine des angemeldeten Users, also z.B. "/home/ralf/.wine". Die Bascom-spezifischen Files liegen dann unter "/home/ralf/.wine/drive_c/Program Files/BASCOM-AVR".
Ggf. muss man im Dateimanager seines Vertrauens erst einmal die Anzeige versteckter Ordner und Files aktivieren.
Will man nur die Kommandozeilenversion bascomp.exe nutzen, kopiert man der Einfachheit halber die relevanten Files in einen neuen Ordner "bascomp" im Heimatverzeichnis, z.B. nach "/home/ralf/bascomp":
- den Ordner LIB
- bascomp.exe
- BASC-AVR.DLL
- BASCAVR.chm (Help-File)
- bscavrl.dll (Lizenzdatei)
- alle *.DAT und *.dat - Files
Man kann auch "exotische" Dat-Files weglassen und lediglich die *.dat-Files für tatsächlich genutzte Mikrocontroller kopieren.
Danach kann man Bascom-AVR deinstallieren (im xterm "wine uninstaller" aufrufen).
Ist auf dem Rechner Windows vorhanden und dort Bascom bereits
installiert, kann man sich die Installation der Bascom-Demo unter Wine
selbstverständlich ersparen und die oben genannten Files dort
"ausborgen".
Gibt man nun in einem Terminal wine ~/bascomp/bascomp.exe ein, sollte sich bascomp mit einem umfangreichen Verwendungshinweis melden:
bascomp command line compiler version 2.0.7.x
supports all existing and future DAT files
DAT Directory :Z:\home\ralf\bascomp\*.DAT
DAT files found :80
Usage : bascomp file.bas SS=softstack FR=framesize HW=hardwarestack CHIP=index
31=ATtiny2313A
91=ATtiny48
100=ATMEGA325
.........
39=ATMega128RFA1
42=ATMega165
19=atmega64
Set baudrate, XTAL, LCD etc. with $ directives and CONFIG in your code
Ihm entnimmt man, dass bascomp ziemlich "doof" ist: die Werte für
SoftStack, Framesize, Hardwarestack und MCU müssen beim Aufruf auf der
Kommandozeile übergeben werden. Man kann das durchaus mit klassischen
Linux-Kommandozeilenwerkzeugen wie grep, sed und awk automatisieren
(ich hatte sogar damit begonnen), aber inzwischen gibt es ein
bascomp-Update, das die Werte direkt aus dem *.bas-File lesen kann,
wenn man bascomp mit dem Parameter "auto" aufruft.
Man lädt das Update
hier
herunter und überschreibt die alte Version "/home/ralf/bascomp/bascomp.exe" mit der neuen Version (die neue ist 113 kB groß, die alte nur 102 kB).
Geany installieren und konfigurieren
"Geany" ist eine kompakte IDE, die weitgehend "ausentwickelt"
ist und sich nur noch wenig ändert. Sie kann auf den gängigen
Linux-Varianten über die Paketverwaltung installiert werden.
Anscheinend kann man ihr aber keine komplett neuen Syntax-Files
"unterschieben". Ich habe daher die Sprache "Freebasic" geopfert und
das File "filetypes.freebasic"
modifiziert. Neben den zusätzlichen Schlüsselwörtern für
Bascom-spezifische Befehle sind auch Schlüsselwörter für einige
AVR-Register dazugekommen.
Außerdem kann man in diesem File auch ein individuelles
Farbschema hinterlegen. Die Farben sind dem BASCOM-Styling
nachempfunden. Schlüsselwörter werden zwar nicht in Blockbuchstaben
umgewandelt, aber trotzdem sieht die Darstellung halbwegs gewohnt aus.
Geany bietet die Möglichkeit, mit dem Pulldown-Menüpunkt "Neu
(aus Vorlage) - file.bas" ein "Leer-Gerüst" zu laden, das im File
"file.bas" vordefiniert wurde.
Über die Geany-Menüpunkte (bzw. die Werkzeugleisten-Icons) "Kompilieren" und "Erstellen" werden die Skripte (Batch-Files) "c-bas" und "c-f-bas"
aufgerufen, die ihre Ausgabe in einem xterm-Fenster präsentieren.
"Erstellen" kompiliert und flasht das entstandene hex-File "in einem
Rutsch".
Skript "c-bas"
Unter Linux werden Zeilenenden nur mit Linefeed (0x0A)
abgeschlossen, unter Windows mit Linefeed + Carriage Return (0x0D).
Bascomp.exe steigt mit einer Fehlermeldung aus, wenn Carriage Returns
fehlen. Der Stream-Editor "sed" ergänzt aufgrund einer kryptischen
Befehlsfolge jedes Linefeed mit einem Carriage Return und schreibt das
Ergebnis in eine Datei programmname.dos.
Diese wird dann an wine/bascomp übergeben. Da wine und bascomp ziemlich
"geschwätzig" sind, schickt das Skript alle Programm- und
Fehlermeldungen ins Nirwana (nach /dev/null).
Zum Abschluss wird geprüft, ob bascomp.exe einen Fehler entdeckt und eine Datei programmname.err
angelegt hat. Diese wird ggf. im xterm ausgegeben. Ansonsten wird
"compilation ok" gemeldet und das Fenster selbsttätig geschlossen.
Skript "c-f-bas"
Im oberen Teil muss man zuerst den verwendeten Programmer
eintragen, im meinem Fall ist es ein USBASP. Auskommentiert sind zwei
Beispiele für einen selbstdefinierten seriellen Programmer
(Franzis-Lernpaket-Mikrocontroller) und meinen alten SP12-Programmer
für die parallele PC-Schnittstelle. Sie können als Beispiel dienen, da
der als aktiv eingetragene USBASP keine besonderen Parameter wie
Schnittstellen-Name oder Baudrate benötigt.
Danach folgt der Programmcode von "c-bas", und dann wird es
kryptisch. Der verwendete Microcontroller soll aus dem *.bas-File
ausgelesen und an avrdude übergeben werden. In einem Bascom-Programm
können Zeilen wie
$regfile = "m8def.dat" ' used microcontroller
' $Regfile="Attiny45.dat"
'$regfile = "attiny13.dat"
stehen - führende Leerzeichen, Groß-Kleinschreibung, angehängte
Kommentare und auskommentierte Zeilen, die erkannt und verworfen werden
müssen. Aus der (gültigen) ersten Zeile darf nur ein schlichtes m8
übrigbleiben.
Verwendet werden nur die Standard-Linux-Bordmittel grep, sed, cut und
tr. Die Kommentare im Skript "c-f-bas" erklären die einzelnen Schritte.
Alles an seinen Platz
Die beiden Skripte müssen in einen Ordner kopiert werden, der
im Suchpfad liegt. Hat man einen ~/bin-Ordner im Home-Verzeichnis,
können sie da rein, ansonsten kopiert man sie nach /usr/local/bin.
Die modifizierten Files "filetypes.freebasic" und "file.bas" gehören in die versteckten Ordner /home/ralf/.config/geany/filedefs bzw. /home/ralf/.config/geany/templates. Optional kann die Datei ui_toolbar.xml nach /home/ralf/.config/geany
kopiert werden, sie blendet ein paar Icons aus der Werkzeugleiste aus.
Nach dem Kopieren sollte man ggf. Eigentümer und Gruppe der Files
anpassen und die Skripte ausführbar machen.
Schließlich muss man noch nach dem Start von Geany unter
"Erstellen - Kommandos zum Erstellen konfigurieren" das Öffnen von
xterms und die Aufrufe der Batch-Files eintragen.
Sollte avrdude nicht mit Userrechten (jedoch mit Rootrechten)
funktionieren, fehlt eine passende udev-Regel für den verwendeten
Programmer unter /etc/udev/rules.d . Wie man sie anlegt, lässt sich schnell "ergoogeln".
Download der Files 0216-bascomp-unter-linux.tar.gz
#! /bin/bash
# Usage: c-f-bas "filename without .bas"
#-------------------------------------
# insert your Programmer here:
# a self defined programmer:
#PROG='burkhard'
#PORT='/dev/ttyS0'
#DLAY='20' # important; slow down the Programmer if the MCU's clock is below 8 MHz
# parallel port programmer "SP12"
#PROG='sp12'
#PORT='/dev/parport0'
# DLAY='10' # important; slow down the Programmer if the MCU's clock is below 8 MHz
# usbasp
PROG='usbasp'
PORT='usb'
DLAY='10'
#-------------------------------------
# We check if a nonexisting filename or no filename was called
# the extension "bas" is added automatically
# the script ends if the filename does not exist
if [ -a ./$1.bas ]; then
echo " compiling ...."
else
echo " empty file or wrong filename "
sleep 2
exit
fi
# if the source code was edited with a linux editor, lines may not end
# with carriage returns. We add them with sed and write into a file
# named "filename.dos":
cat $1.bas | sed 's/$'"/`echo \\\r`/" > $1.dos 2> /dev/null
# We call bascomp and hand over the filename:
# all bascom outputs are sent to /dev/null
wine ~/bascomp/bascomp.exe $1.dos auto 2> /dev/null 1> /dev/null
# now we print "ok" if the source was compiled
# or print the content of the error file and exit (if compilation failed):
if [ -a ./$1.err ]; then
cat ./$1.err
sleep 3
exit
else
echo " compilation ok "
# sleep 1
fi
#-------------------------------------
# here the avrdude part starts:
# we try to cut out the name of the micocontroller from the *.bas file
# first "sed" command deletes all blanks from the lines
# first "grep" deletes all $regfile statements that have been commented out (like '$regfile )
# second "grep" extracts the line containing $regfile
# first "cut" cuts out the second expression after the delimiter "="
# second "cut" cuts off comments at the and of the valid $regfile line
# "tr" transforms upper case letters to lowercase letters
# second "sed" deletes the carriage return
# now we have an expression like "m8def.dat"
REG=$( sed 's/ //g' $1.bas | grep -v "^'$regfile" | grep '$regfile' | cut -d "=" -f 2 | cut -d "'" -f 1 | tr A-Z a-z | sed 's/\r//' )
# the "PART" name that avrdude expects is somewhat different from the regfile's micocontroller name
# so first sed deletes "def" (like in m8def.dat)
# second sed deletes ".dat"
# now we have an expression like "m8"
# last cut removes "" - it cuts out m8 - this is the form avrdude expects
PART="none"
PART=$( echo $REG | sed 's/def//g' | sed 's/.dat//g' | cut -d '"' -f2 )
# now we check if "PART" is empty or "none"
if [ -z $PART ]; then
echo "Sorry - no valid microcontroller name was handed over to avrdude!"
sleep 5
exit
fi
if [ $PART = "none" ]; then
echo "Sorry - no valid microcontroller name was handed over to avrdude!"
sleep 5
exit
fi
if [ -z $DLAY ]; then
avrdude -p $PART -c $PROG -P $PORT -U flash:w:$1.hex:i
else
avrdude -p $PART -c $PROG -P $PORT -B $DLAY -U flash:w:$1.hex:i
fi
sleep 3 # we leave the avrdude output on the screen for 3 seconds