Kleines Dateisystem für Mikrocontroller

Beim portieren einer C-Bibliothek vom PC auf einen Mikrocontroller bin ich auf ein Problem gestoßen: Die Bibliothek arbeitet mit Konfigurationsdateien die zuvor geladen werden müssen. Das Umschreiben der Lib wäre sehr aufwändig gewesen und der Quellcode danach nicht mehr kompatibel, also nicht mehr wartbar, wenn eine neuere Version herauskommen.

Eine andere Lösung ist es die verwendeten Dateifunktionen (fopen, fscanf, fclose) zu implementieren und ein „virtuelles Dateisystem“ vorzugaukeln. Wobei doch irgendwie jedes Dateisystem virtuell und abstrahiert daher kommt…

Als erstes habe ich natürlich das Netz nach bereits umgesetzten Lösungen abgesucht und leider nichts gefunden (Tipps gern per Kommentar). Also musste ich mir was eigenes schreiben.

Verwendet man einen CortexM Mikrocontroller, kann man auf den Luxus einer bereits portierten newlib zurückgreifen und die POSIX-konformen Dateiaufrufe verebben in den sogenannten syscalls. Die syscalls können auch als Backend für die libc-Funktionen betrachten werden und die Funktion der syscalls werden von einem Betriebssystem auf entsprechende Ressourcen umgeleitet.

Die syscalls stellen z.B. einen bequemen Weg bereit über den printf-Aufruf Debugnachrichten auf ein UART-Interface umzuleiten. Dazu sollte die Datei syscalls.c mit der Minimal-Variante in das Projekt eingefügt werden (Linkereinstellungen der newlib beachten!). Anschließend werden in der write-Funktion die übergebenen Zeichen auf die gewünschte UART weitergeleitet.

Ganz ähnlich funktioniert die read-Funktion. Es wird nach einer bestimmten Anzahl von Zeichen gefragt. Diese sind aus dem übergebenen Datei-Diskriptor zu laden. Für stdin, stdout und stderr sind die Diskriptoren festgelegt und müssen nicht geöffnet werden, bevor gelesen oder geschrieben wird. Eine geöffnete Datei muss ebenfalls vom Betriebssystem einen Diskriptor zugewiesen bekommen, also einen unverwechselbaren File-Handle.

Nun ist es jedoch so, dass es kein Dateisystem auf dem Mikrocontroller gibt und damit auch keine Implementierung die auf ein fopen etwas anderes als ein -1, also Fehler beim Öffnen, zurückliefern kann. Dazu die Minimal-Implementierung der newlib syscalls:

int open(const char *name, int flags, int mode) {
    return -1;
}

Nun sind die nötigen Funktionen schon fast ausfindig gemacht. Weiterhin wichtig für ein Dateihandling, ist eine Funktion um in einer Datei den Lese-/Schreibpointer zu setzen: lseek. Diese wird nicht nur durch manuelles setzen des Pointers angesprungen (fseek), sondern auch durch den Aufruf von fscanf.

Der Ablauf zum Lesen einer Datei ist also folgendermaßen:

Wir rufen fopen auf und wollen eine Datei mit dem gegebenen Pfad/Dateinamen öffnen. Der Befehl landet in der open-Funktion der syscalls.c.

Implementierung open: Vergleichen des Dateinamens mit einer internen Dateiliste und beim Vorhandensein der Datei wird ein File-Pointer zurückgegeben (ungleich 0, 1 oder 2). Ein interner Zeiger wird auf den Anfang der Datei/Speicherstelle gesetzt.

Mit fscanf wird ein Parameter aus der Datei eingelesen.

Implementierung read: Vergleichen ob der übergebene File-Pointer einer geöffneten Datei angehört. Lesen der Datei/Speicherstelle ab der zuletzt bekannten Position.

Implementierung lseek: Vergleichen ob der übergebene File-Pointer einer geöffneten Datei angehört. Setzen des File-Pointers unter Berücksichtigung der Dateigrenzen.

Mit fclose wird die Datei wieder geschlossen.

Implementierung close: Vergleichen ob der übergebene File-Pointer einer geöffneten Datei angehört. Die virtuelle Datei wird als geschlossen markiert.

Mit fwrite in eine Datei schreiben.

Implementierung write: Soweit habe ich das kleine Dateisystem nicht getrieben. Da ein Flash-Page Write und Errase besonders Handling benötigt, würde diese Implementierung auch etwas aufwändiger ausfallen, als nur vom Flash zu lesen. Damit ist das Dateisystem bisher read-only!

Die Datei auf dem Mikrocontroller abzulegen ist übrigens recht einfach. Zum Beispiel auf dieser Seite kann eine Datei in ein const char array gewandelt werden. Dies wird dann in eine Header-Datei abgelegt und der Pointer auf das Array und die Länge der Datei wird in einer Struktur eingearbeitet. Diese Struktur repräsentiert das Dateisystem, im Grunde eine sehr simple File Allocation Table (FAT).

Das Hinzufügen einer neuen Datei erfolgt so:

  1. Datei in char-Array wandeln: http://fuxx.h1.ru/bin2c/index.en.php
  2. Datei/char-Array in einer Header-Datei speichern (im Github-Beispiel: my_config_files.h)
  3. Dateiname, -pointer und -größe in flash_fs.c Struktur eintragen und define mit der Anzahl an Dateien inkrementieren:
#define FILE_FS_NUMBER_OF_FILES 2
static const char *file_names[FILE_FS_NUMBER_OF_FILES] =
{
 "config.txt",
 "config_dbg.txt"
};

flash_file my_files[FILE_FS_NUMBER_OF_FILES] =
{
 {
 config_txt, sizeof(config_txt), -1, 0
 },
 {
 config_dbg_txt, sizeof(config_dbg_txt), -1, 0
 }
};

Anschließend kann die Datei im Programm, ähnlich wie von einem PC gewohnt, verarbeitet werden:

FILE *cfg = fopen(„config.txt“, „r“);
int reading;
fscanf(cfg,“PWMDutyCycle=%d\n“, &reading);
fclose(cfg);

Das komplette Demo-Projekt für das STM32F4 Discovery-Board gibt es auf meinem Github-Account:

https://github.com/Counterfeiter/CortexM-read-only-FileSystem

Limitierungen und mögliche Drawbacks des aktuellen Dateisystems:

  • kein binäres Dateihandling möglich
  • kein Schreiben von Dateien möglich
  • die newlib reserviert dynamischen Speicher im Hintergrund

Vorteile:

  • benötigt nur sehr wenig Flash/RAM (Demoprojekt: 14 KByte Flash)
  • wird das Dateisystem nicht benötigt, wird in der syscalls.c die Headerdatei (flash_fs.h) einfach nicht inkludiert
  • stdin/stdout/stderr können weiterhin parallel verwendet werden (Debug printf)
  • Bibliotheken die für den PC geschrieben wurden und auf Dateien lesen möchten können einfacher für den Mikrocontroller portiert werden.

Wer möchte kann das Dateisystem gern weiter optimieren. Meine Ideen wären:

  • Schreiben von Dateien als RAM-Kopie oder direkt in den Flash
  • Erstellen eines PC-Programms, um alle Dateien eines Ordners schnell in eine Header-Datei zu überführen und die nötige Struktur automatisch zu erstellen -> Einbindung in den Build-Prozess
  • Dateien als verkette Liste ablegen -> ersten 4 Byte nicht 0, dann ist es Pointer auf nächste Datei

Tipp: Wer mit der newlib Fließkommazahlen lesen und schreiben will, muss folgende Linker-Flags setzen:

-u _printf_float -u _scanf_float
Veröffentlicht unter Allgemein | 1 Kommentar

Experimente mit Ferrofluid

Ich bin es gewohnt, dass jedes meiner Projekte irgendwie seine gewünschte Funktion erfüllt (irgendwann). Zum einen liegt es wohl daran, dass ich nicht einfach darauf los bastle, sondern schon etwas länger ein Konzept ausarbeite, aber auch viel simuliere, bevor ich die ersten Bauteile bestelle. Da ich auch beruflich als Elektronikentwickler arbeite, ist das natürlich das übliche Vorgehen im Ingenieurbüro.

Dabei ist gegen das reine Basteln natürlich auch nichts einzuwenden. Also einfach darauf los bauen und wenn etwas nicht geht, einen Workaround finden, damit es funktioniert. Basteln ist also die kreativere Arbeit bei der man noch viel lernen kann und wenn in beispielsweise 5 % der Fälle ein besserer Workaround entsteht, als es ein gutes vorgedachtes Konzept abdeckt, ist es um so erstaunlicher. Für Private ist also eine gesunde Mischung aus „darauf los basteln“ und kleine Konzepte entwickeln am besten geeignet. Beruflich kann man sich es nicht leisten eine Entwicklung in die falsche Richtung zu lenken. Hier sind 30 % der Zeit für eine Definitions- und Konzeptphase Pflicht. Wer mehr über meinen Arbeitsalltag wissen möchte, kann ja einen Kommentar da lassen- evtl. kann ich dann in diese Richtung was bloggen.

Zum Thema! Dieses Projekt ist nicht so perfekt verlaufen, wie ich es mir vorgenommen habe.

Ferrofluid ist eine Flüssigkeit die größtenteils aus Öl und Nano-Ferromagnetischen-Partikeln besteht. Ob Nano hier nur ein Werbeargument ist und es einfach nur feiner Eisenstaub ist, kann ich nicht beurteilen. Es gibt aber definitiv sehr unterschiedliche Flüssigkeiten mit verschiedenen Eigenschaften. Angeregt durch ein paar schöne Ferrofluid-Videos musste ich das auch haben!

Beispiele:

Mein Gedanke dazu: „Kann ja nicht so schwer sein mit einer Spule/Spulenmatrix ein Magnetfeld zu erzeugen.“

Ferrorfluid kostet aber leider ein kleines Vermögen und wie viel braucht man davon überhaupt? Der kleine „Shot“ (20 ml) kostet schon 18 €. Reicht das denn für mein Vorhaben?

Mein Vorhaben war es ein aus Stahl gelasertes Herz mit zwei innenliegenden Buchstaben von Ferrofluid interaktiv umfließen zu lassen. Es sollte ein Hochzeitsgeschenk für meine Schwester und ihren Freund werden.

Da Ferrofluid so aggressive Flecken wie Rost hinterlässt und auch von der Haut nicht so leicht abwaschbar ist, habe ich ein kleines Aquarium bei Ebay-Kleinanzeigen erstanden. Es stellte sich aber schnell heraus, dass für die erste Version ein deutlich kleinere transportablere Variante gebaut werden muss. Nun habe ich im Supermarkt ein rechteckiges Glas gesucht, dass damit bessere optische Eigenschaften besitzt als ein rundes. Es war gar nicht so leicht ein solches Glas zu finden. Zum Schluss gab es eins mit Himbeermarmelade. Lecker!

Das Beseitigen der Etiketten vom Glas war allerdings sehr aufwändig, weil ich vorher nicht gegoogelt hatte. Ich kannte zwei Möglichkeiten: Mit einem Föhn den Aufkleber erwärmen und dann in einem Stück abziehen. Das ging leider nicht. Nun habe ich mit Lösungsmittel wie Aceton gekämpft. Es wollte einfach nicht sauber abgehen. Bis ich mich informiert habe und es je nach Klebstoffart noch eine weitere Möglichkeit gab. Öl! Ich wollte es zwar nicht so recht glauben, aber als ich den Aufkleber mit Sonnenblumenöl und etwas Druck abreiben konnte, war ich baff.

IMG_2785

Mit Speiseöl konnte ich den Aufkleber vom Glas sauber entfernen.

In Vorbereitung auf die doch größere Investitionssumme habe ich mir das kostenlose Programm FEMM 4.2 besorgt und meine ersten Experimente damit unternommen. Das Programm lässt sich nicht sehr intuitive bedienen und kann leider nur zweidimensionale Finite-Elemente-Probleme simulieren. Mit zwei YouTube-Videos zur Bedienung habe ich dann den Einstieg doch recht schnell hinbekommen.

Mit Tinkercad, ein online 3D-Tool mit eingeschränkten Funktionsumfang, konnte ich eine Laserschablone im *.dxf Format erstellen und diese auch direkt als Vorlage ins FEMM importieren. Die Simulation zeigte, dass das Ferrofluid Stacheln am Herzrand erzeugen sollte. Das Simulationsergebnis der Magnetfeldlinien habe ich direkt in das Design der „Plattform“ mit einfließen lassen:

IMG_2807

Der Elektromagnet unter dem Metallherz ist eine Weichenspule von Reichelt, die möglichst viele Windungen, also Induktivität, haben sollte. Ein starker Draht sorgt für eine geringe Verlustleistung. Bei welchem Strom die Spule in die Sättigung geht, weiß ich leider nicht. Darüber gibt es keine Angaben durch den Hersteller.

Der Eisenkern der Spule bündelt das Magnetfeld und „schickt“ es direkt in das darüber stehende Metall, sagt die Simulation. Meine zweite Option war es, den Eisenkern der gekauften Spule herauszuschlagen. Das habe ich jedoch bis heute nicht probiert.

Es soll ja interaktiv werden. Also brauchte ich einen einstellbaren Elektromagneten. Die Stärke eines Elektromagneten stellt man über den Strom ein. Lösung: eine stellbare Stromquelle. Der Sollwert wird in meiner Version durch einen Entfernungsmesser von Sharp vorgegeben. Da der Sollwert bereits analog vorliegt, wollte ich die Schaltung zeitsparend ohne Mikrocontroller aufbauen. Wieder habe ich simuliert, diesmal eine geeignete Schaltung mit LTSpice. Herausgekommen ist folgende reine OPV-Schaltung:

OPV_Schaltung

Ein OPV in Schmitt-Trigger-Schaltung steuert mit einem P-Kanal-MOSFET die Induktivität L1 über eine 12 V Versorgungsspannung an. Das langsame Sinussignal V2 simuliert dabei das wechselnde Ausgangssignal des Entfernungsmessers und R8 ist der Messshunt der die Stromstärke rückkoppelt. Die Widerstandswerte müssen nur so angepasst werden, dass sich der gewünschte Strom an der Spule einstellt. Mit der gezeigten Widerstandskonfiguration ist ein maximaler Strom von 1,5 A mit dem Sharp-Sensor möglich. Einen NTC-Widerstand mit einzubinden, der den Strom reduziert, wenn die Schaltung sich zu stark erwärmt, ist möglich, wurde aber von mir wieder verworfen. An die Grenzbereiche des machbaren Stromes bin ich nicht gegangen, die Spule erwärmt sich allerdings schon deutlich auf ca. 45 °C. Was jedoch nicht kritisch ist.

Leider wird mit dieser Schaltung auch der P-MOS recht schnell warm, da er vom OPV nicht so sauber getrieben wird, wie ich es erhofft hatte. Eine weitere Alternative ist eine Stromquelle mit dem MC34063 aufzubauen. Dabei gibt es keine Ausgangslast (Kurzschluss), da nur der Strom durch die Spule interessant ist. Das Problem des MC34063 ist, dass die Sollwertvorgabe über eine interne Referenz von 1,25 V erfolgt. Zum Glück gibt es eine Version des Schaltreglers (z.B. LM78S40) wo alle Komponenten einzeln zugänglich sind und diese selbstständig verbunden werden müssen. Statt der Referenzspannung wird einfach die heruntergeteilte Spannung der Lichtschranke am Comperator angeschlossen und fertig.

Was mir noch fehlte war also das Ferrofluid. Einer der wenigen Hersteller ist die US-Firma FerroTec, die auch eine deutsche Niederlassung besitzt. Warum also die teuren Umwege über Zwischenhändler? Direkt beim Hersteller ordern ist doch viel billiger! Ein kurzes Telefonat ergab: Mindestabnahmemenge 1 Liter. Zum Preis von 230 € brutto. Das ist zwar im Vergleich zu den üblichen Mindermengen ein guter Preis, aber viel zu viel Fluid. Also mein Vorhaben und die Sache mit der Hochzeit erklärt. Die freundlichen Mitarbeiter haben dann eine Ausnahme gemacht, da es noch eine 0,6 Liter Flasche im Lager gab. Diese habe ich in der Erwartung gekauft, dass ich doch noch so viel damit vor habe…

Die ersten Versuche mit dem Fluid waren allerdings schon sehr ernüchternd. Der Elektromagnet hatte eine sehr schwache Wirkung auf das Fluid. Um das Fluid etwas in der Bewegung zu unterstützen habe ich das Glas mit Wasser aufgefüllt. Schon etwas besser! Ein weiteres Problem war, die Scheibe des Glases war sofort vom Ferrofluid dreckig und man konnte kaum noch durchschauen. Die Lösung war etwas Spülmittel im Wasser. Spülmittel löst bekanntlich Fette, das Fluid besteht aus Öl. Das Ergebnis ist eine sauberes Glas, jedoch ein Fluid das eher dazu neigt kleine Tropfen zu bilden, statt im ganzen zu agieren.

Wie eingangs erwähnt, ist es kein kompletter FAIL gewesen, jedoch ist es das Projekt mit dem schlechtesten Preis-/Leistungsverhältnis das ich jemals durchgeführt habe.

Im Vergleich zu den schönen Videos oben, ist meine Variante eher ein Tropfen auf den heißen Stein:

Hier noch ein paar Bilder vom Aufbau:

 

Eine weitere bessere Möglichkeit ist übrigens starke Dauermagneten zu verwenden. Diese können auch interaktiv verwendet werden, wenn sie mit starken Servomotoren bewegt werden. Mein Interesse ist aber erst einmal gesättigt. 😉

Wie aus dem Beitrag hervor geht, sitze ich noch auf einem riesigem „Topf“ Ferrofluid. Wer mindestens 100 ml abnehmen möchte, darf mich gern anschreiben. Ich kann einen guten Preis machen!

Veröffentlicht unter Allgemein | 11 Kommentare

WeddingBot / Nespresso® Bot

Wir heiraten heute am 01.07.2016 und als Gastgeschenke für unsere Gäste soll es etwas ganz Persönliches geben. Da meine (zukünftige) Frau Mandy gern mit Papier und Schere bastelt und ich natürlich gern an Elektronik, haben wir beides kombiniert.

Herausgekommen ist eine kleiner Roboter in schicker Verpackung für Hochzeiten oder andere Festlichkeiten, der „singen“ und mit den Augen funkeln kann. Außerdem geht er schlafen, wenn es dunkel wird. Das der Bot, wenn man ihn mit seinem Besteck oder etwas anderem leitfähigem aktiviert, schon so für Stimmung sorgt, ist durch die unterschiedlichen Töne und ganzen Lieder sichergestellt. Wir hätten hier klassisch „Für Elise“ oder passend zum Thema „Mendelssohn – Wedding March“. Zwischen drin kommt aber auch mal die „Batman Theme“ und andere kurze Sweeps oder Fanfahren, damit es nicht zu „steif“ auf der Feier zugeht.

Damit die Party in Schwung kommt, sollten die Gäste am besten mit Gruppenspielen beschäftigt werden, aber mögen das Alle? Für unseren ganz persönlichen Gruß an unsere lieben Hochzeitsgäste hat der Wedding Bot auch noch eine weitere Funktion. In zufälligen Intervallen wird „unsichtbar“ über die LED-Augen eine ID ausgegeben. Diese kann von einer Basisstation = Raspberry Pi mit Lichtsensor interpretiert werden. Ein kleines Python-Programm stellt passend zur ID ein Bild auf einem Monitor dar. Der Kreativität des Hochzeitspärchens sind nun keine Grenzen gesetzt.

Wir haben uns für folgende Variante entschieden: Kein Hochzeitsgast bekommt den richtigen Bot und jeder Bot sollte seinen Besitzer finden, indem die Gäste zur Basisstation gehen und sich ein Bild des Besitzers ansehen. Danach muss dieser natürlich aufgesucht werden und der Bot getauscht. Die Bilder können witzig oder förmlich sein, alt oder neu. Das kann alles individuell entschieden werden. Man könnte durchaus auch Rätselfragen präsentieren, wenn man das möchte.

Damit überhaupt Interesse an einem Tausch entsteht, müssen alle (nennen wir sie an der Stelle wieder) NespressoBots auch unterschiedlich aussehen. Also personalisiert sein. Dazu hatten wir die Idee, als günstiges und praktisches Gehäuse, was zudem noch super schick aussehen kann, eine leere Nespresso-Kapsel zu nehmen. Dazu haben wir diese einfach nach dem trinken vom Kaffee befreit. Zusätzlich habe ich noch alle Bots eine individuelle handgemalte Frisur verpasst. Tada: ein Unikat.

Weiter oben steht wie der Bot angeht. Wie geht er eigentlich aus? 60 Gäste mit trötendem Bot kann auf die Dauer auch nerven ;). Der Bot macht es eigentlich wie der Mensch, wenn es dunkel wird schläft er nach ca. 2 bis 3 Minuten (alles zufallabhängig) wieder ein. Also einfach zurück in die Schachtel packen. Ob man das den Gästen sagt oder ob die es lieber selbst herausfinden sollen, da sind wir uns auch noch uneinig. 😀

Wenn man über 60 Gastgeschenke baut, dann sucht man schon nach Möglichkeiten das Budget und vor allem den Aufwand möglichst klein zu halten. Das heißt: wenig Bauteile, einfach zusammen zubringen.

Nach einigen Optimierungsschritten besteht die Minimalbeschaltung aus nur acht Elektronikbauteilen und der Kapsel und PCB:

  • zwei LEDs
  • drei gleiche Vorwiderstände
  • Mikrocontroller ATTiny45
  • Batteriehalter
  • Piezo-Speaker
  • Nespresso-Kapsel, Platine

Hier der Aufbau für die Hochzeit, mit noch deutlich mehr Bauteilen (+ 3 x NPN Transistoren).

Hier noch der Aufbau der Basisstation:

Der Monitor wird natürlich noch etwas festlicher dekoriert! Das Zuhause des Bots in passenden Mottofarben rundet dann das gesamte Design ab.

IMG_3543

Im laufe der Vorbereitungen gab es noch weitere Optimierungsschritte und man kann auch weiterhin Dinge verbessern. Die Iterationen sind auch bei diesem kleinen Projekt nicht zu unterschätzen. In der neusten Variante sind durch Einsatz einer kleineren und leider teureren Batterie alle Komponenten auf der Rückseite. Da man die PCB so gut bemalen oder mit kleinen Stickern bekleben kann, habe ich das Design sehr allgemein gehalten. Mit unterschiedlichen LED-Farben habe ich ebenfalls experimentiert.

nespresso

Veröffentlicht unter Allgemein, WeddingBot | 6 Kommentare

ATTiny, ATMega UART Bootloader

Für ein kleines Projekt war in der Startphase ein Bootloader ganz praktisch. Unhandlich ist es mit Atmel ISP bzw. SPI Header auf der Platine einen Mikrocontroller zu programmieren. ISP braucht einfach zu viele Signale (6) -> VCC, GND, Clock, Reset, MISO, MOSI.

Die Lösung war der Bootloader von Peter Dannegger. Der Bootloader ist klein, schnell und unterstützt sogar den OneWire-Betrieb. Leider gibt es auf dem Mirkocontroller.net Forum ein ziemlich Wildwuchs an unterschiedlichsten Versionen, Dokumentation und auch PC-Tools, sowohl für Windows als auch Linux.

Trotz der zahlreichen Wiki-Seiten hat es mich Stunden gekostet hier durchzusteigen und die Versionen und Hardwareaufbauten zu finden die zusammen passen. Hier die Wiki-Seiten, sollte ihr diese nach meiner Kurzanleitung noch benötigen:

http://www.mikrocontroller.net/articles/AVR_Bootloader_FastBoot_von_Peter_Dannegger

http://www.mikrocontroller.net/articles/AVR_Bootloader_FastBoot_von_Peter_Dannegger/Tutorial_ATtiny13

Dazu gibt es noch einige seeeehr lange Forumsbeiträge, die man sich ergooglen kann.

Ich möchte hier nur auf den OneWire-Betrieb mit Windows eingehen und es kurz und schmerzlos ohne viel Prosa machen:

  • das meiner Meinung nach einzige funktionierende Windowstool für OneWire ist der UpdateLoader: https://luani.de/projekte/updateloader/
    • Password sollte standard „Peda“ sein -> Achtung keine beliebige Passwortauswahl möglich, da es mit dem Autobauding zusammenhängt
    • Bei „Erweitert“ natürlich OneWire aktivieren
  • Bootloader richtig konfigurieren und kompilieren
    • nur die Datei BOOTLOAD.ASM bearbeiten
    • passende include zum Prozessor einkommentieren
    • TX und RX PIN muss für OneWire gleich angegeben werden
    • der Pin ist frei wählbar, da Software-UART
    • der Bootloader wartet nach dem Prozessorstart kurz und wenn keine Programmieranfrage kommt, wird das Hauptprogramm geladen. Wollt ihr die Wartezeit beeinflussen (kein Muss) oder habt einen stark abweichenden Clock zu 8 MHz, dann in der FASTLOAD.H -> BootDelay bearbeiten
  • Programmierhardware
    • Schaltung für RS232-Wandler (+/- 12 bis 3 Volt Pegel): http://www.mikrocontroller.net/attachment/24979/bootloader.pdf
    • wer einen USB/UART Wandler wie ich benutzen möchte, muss zwingend die RX und TX Signale invertieren. Bei einem FTDI kann dies ganz einfach mit dem Windows-Konfigtool des FTDIs erledigt werden. Bei einem billigem Wandler wie ich ihn habe, musste ein 74HTC04 Inverter zwischen USB/UART und Mikrocontroller gebracht werden.
    • Die weitere Beschaltung habe ich im Mikrocontroller-Forum leider nirgends gefunden, daher meine Version:
    • onewire_fboot
    • mindestens 19,2 kbaud sollten mit dieser „langsam“ wirkenden Schaltung möglich sein

Für die Programmierhardware habe ich mir noch etwas besonderes einfallen lassen. Einfach am Rand der PCB zwei 2 mm große Testpunkte einfügen und diese mit GND und Programmierpin verbinden. Nun habe ich eine Klammer in der Mitte aufgesägt und zwei schräg abgeschnittene 1,5 mm² Kupferader befestigt. Durch die Halbierung der Klammer, können die Pins getrennt voneinander federn.

Im Bild habe ich eine Beispiel-PCB verwendet. Die Pins sind natürlich von einem USB-Connector.

Insgesamt ist es keine schwierige Sache mit dem Bootloader, nur die Informationen sind sehr verstreut.

Veröffentlicht unter Allgemein | 2 Kommentare

srecord und Firmware-Bin’s

Zuletzt hatte ich folgende Aufgabenstellung zu bewältigen:

Eine Firmware sollte eine fortlaufende ansteigende Variable pro geflashten Mikrocontroller enthalten. Also eine sogenannte UID. Es durfte aber nicht irgendeine sein, sondern diese musste zwingend bei 0 beginnen und ca. 100 PCBs würden mir reichen. Irgendwelche internen UIDs des Mikrocontrollers konnte ich demnach nicht verwenden.

Es gibt dafür einen Guten und ein paar weniger gute Ansätze.

Jetzt könnte man meinen für 100 PCBs könnte ich die Variable auch manuell erhöhen und immer wieder neu kompilieren. Problematisch wird es nur, wenn eine neue Firmwareversion erstellt werden muss, weil in der Alten Bugs enthalten waren oder weitere Optimierungen hinzugekommen sind. Dann geht das Spielchen wieder von vorn los.

Also lieber gleich den richtigen Weg gehen. Mit dem Tool srec für Windows und Unix kann eine (nahezu) beliebige binäre Firmwaredatei verändert werden. Das gebräuchlichste Format ist wohl Intel-Hex. Da ich srec am Beispiel von Atmel Studio zeigen möchte, ist dies unser Zielformat. Es wird aber ebenso bei ARM GCC und allen Arduino’s eingesetzt.

Vorbereitungen im Atmel Studio

Um eine Variable gezielt in der Binärdatei zu finden und zu verändern, sollte diese natürlich immer an der selben Speicherstelle stehen. Da Compiler und Linker das ohne Vorgaben für sich entscheiden, sollte dies natürlich angepasst werden.

Die Variable muss beim gcc mit dem attribute section deklariert werden. Die Sektion kann frei gewählt werden. z.B.

const uint8_t my_id __attribute__ ((section (".my_segment"))) = 0xFA;

Ich habe als Wert absichtlich 0xFA gewählt, so ist der Wiedererkennungswert höher als mit 0x00 oder 0xFF.

Nachdem die Variable im Quellcode deklariert ist, muss dem Linker gesagt werden, welche Sektion adressiert werden soll. Da man sich beim Atmel Studio nicht mit einem Linkerscript herumschlagen muss, gibt es unter Properties-> Toolchain -> AVR/GNU Linker -> Memory Settings die passenden Optionen. Bei „FLASH segment“ kann ein neuer Eintrag vorgenommen werden. Für einen ATTINY startet der Flash bei 0x0 und wird Wortweise adressiert. Die Variable an die letzte verfügbare Flashadresse zu legen, macht am meisten Sinn. Bei einem 4 KB ATTINY45 sieht die Berechnung wie folgt aus:

4 KB = 0xFFF -> Wortadressiert -> 0xFFF / 2 = 0x7FF

Wir fügen also folgenden Eintrag hinzu:

.my_segment=0x0007FF

Das Projekt kann jetzt kompiliert und gelinkt werden.

srec_cat anwenden

Download und ausführlichste Informationen gibt es hier: http://srecord.sourceforge.net/

Trotz der ausführlich scheinenden Doku ist das Tool so umfangreich, dass ich nach einigen Funktionen lange suchen musst und mich dann mehr oder weniger mit Try-und Error durchgeschlagen habe.

Als erstes wäre es schön zu sehen, ob ein 0xFA an der erhofften Speicherstelle liegt. Sollte man dies nicht direkt aus dem Intel-Hex ablesen wollen, kann auch eine Binärdatei aus der Intel-Hex-Datei ableitet und sich im Hexeditor ansehen werden.

srec_cat firmware.hex -intel -o firmware_binary.bin -binary

Weiterhin kann die Größe der erzeugten Datei als weitere Verifikation benutzt werden. Da an die letzte Flash-Adresse geschrieben wurde, bei einem 4 KB Flash, muss die Datei nun genau 4 KB – 1 Byte groß sein, da nur 8 Bit der 16 Bit großen Speicherzelle verwendet wurden! Der Aufruf ist an dieser Stelle noch recht simpel. Die einzulesende Datei wird als Intel-hex bekannt gemacht und die Ausgabedatei wird binär erwünscht.

Nun soll das 0xFA überschrieben werden. Dazu wird der Parameter -generate verwendet. Dieser gibt erstellt mit -constan-l-e eine gewünschte Konstante an der richtigen Flash-Adresse. Achtung: Die Adresse wird nun wieder Byte-Adressiert eingegeben.

Wir versuchen einen Trockenlauf:

srec_cat -generate 0x0FFE 0x0FFF -constan-l-e 7 1 firmware.hex -intel -o output.hex -intel

Der Befehl schlägt fehl, weil die Adresse an der die 1 Byte große Variable „7“ geschrieben werden soll schon belegt ist.

srec_cat: firmware.hex: 184: multiple 0x00000FFE values (previous =
 0x07, this one = 0xFA)

Wird 0xFA angezeigt, sollte die richtige Speicherstelle gefunden sein. Das Überschreiben des Wertes gelingt mit dem Parameter -exclude:

srec_cat -generate 0x0FFE 0x0FFF -constan-l-e 7 1 firmware.hex -intel -exclude 0x0FFE 0x0FFF -o output.hex -intel -line-length=44 -address-length=2

Um die Erklärung etwas abzukürzen, habe ich direkt zwei weitere Parameter angehangen. Diese bewirken, dass der Adressraum nur mit 16 Bit angegeben wird und das auf eine Intel-hex Zeile nur eine begrenzte Anzahl an Zeichen eingefügt werden darf. In diesem Fall also 44 Zeichen pro Zeile. Einige Bootloader sind recht einfach geschrieben und benötigen (zu recht) keinen komplexen Parser. Sollte der Bootloader eurer Wahl also Probleme mit der genierten Datei bekommen, solltet ihr die Darstellung der Eingangs- und Ausgangsdatei vergleichen und evlt. die letzten Parameter anpassen.

Um einen hohen Automatisierungsgrad zu erreichen, habe ich noch eine Windows-Batchdatei erstellt, um mir 100 Hexdateien mit aufsteigender UID zu genieren. Einmal ausgeführt und schon sind 100 Dateien im Ausgabeordner:

for /l %%x in (0, 1, 100) do (
srec_cat -generate 0x0FFE 0x0FFF -constan-l-e %%x 1 Debug\firmware.hex -intel -exclude 0x0FFE 0x0FFF -o bins\output%%x.hex -intel -line-length=44 -address-length=2
)

 

 

Veröffentlicht unter Allgemein | Kommentar hinterlassen

mit Biss

Zu Dingen, die einem viel zu selten in die Hände fallen, gehört eindeutig der eigene Gebissabdruck als Negativ und in Gips.

Diese Woche beim Zahnarzt habe ich von meinem Unterkiefer gleich zwei Abdrücke geschenkt bekommen. Okay, die passen jetzt nicht wirklich perfekt aufeinander, aber man kann damit schon ein Gebiss formen.

Zutaten:

  • IR-Näherungssensor von Sharp
  • kleiner Servomotor
  • Tiva-C Launchpad mit Energia Sketch
  • Trinkhalm, Hölzer,  Zahnstocher, Pappkarton, Geschenkpapier und viel Heißkleber
  • und natürlich zwei Gebissabdrücke

Aufbau:

Wirklich schwierig ist es irgendetwas an den Gipsabdrücken zu befestigen. Wenn ihr keinen Zwei-Komponenten-Harz zur Hand habt, wie ich, dann nehmt vieeelll Heißkleber.

Eine Holzkonstruktion dient als Halterung des Gesamtkunstwerkes, daran wird der Servo und der Näherungssensor befestigt. Der Näherungssensor muss gut ausgerichtet werden, so dass er auch mit halb geschlossenem Gebiss noch gut nach draußen „sehen“ kann. Die Trinkhalme habe ich als Scharnier verwendet, vielleicht fällt euch auch noch was besseres ein. Der Faden wird am Oberkiefer befestigt und durch den Servo geführt.

Eine Pappschachtel soll das Arduino / Energia Board beherbergen. Ich habe leider nur das große Tiva-C da gehabt. Der Karton sollte wenigstens ein bisschen nach was aussehen, daher habe ich es in Geschenkpapier eingepackt.

Der Sketch ist so primitiv, der kommt nicht auf meinen Github-Account:

#include <Servo.h> 
 
Servo myservo; // create servo object to control a servo 
int pos = 0; // variable to store the servo position 
 
void setup() 
{ 
 myservo.attach(63); // attaches the servo on pin 9 to the servo object 
 Serial.begin(9600); // setup serial
}

#define MIN_POS 20
#define MAX_POS 120

void loop() 
{ 
 int analog = analogRead(23);
 Serial.println(analog);
 if(analog > 2000 && analog < 2600) {
 analog -= 2000;
 analog /= 30;
 analog += MIN_POS;
 myservo.write(analog); 
 delay(10); 
 
 } else if(analog >= 2600) {
 myservo.write(120);
 delay(2000); 
 for(pos = MAX_POS; pos >= MIN_POS; pos--) 
 { 
 myservo.write(pos); 
 delay(5); 
 } 
 }
}

Elektrisch ist nicht viel zu tun. Sowohl der Servo als auch der Näherungssensor werden mit 5 Volt versorgt. Servo an möglichen Servo-Ausgang und Näherungssensor an einen ADC-Eingang. Fertig!

Wenn der mechanische Aufbau nicht seine Tücken gehabt hätte, wäre alles in 30 Minuten fertig gewesen. So hat es doch zwei Stunden bis zum gewünschten Ergebnis gedauert.

Hier nun das Ergebnis:

 

Veröffentlicht unter Allgemein | Kommentar hinterlassen

Musikalischer ATTiny

Für ein Projekt habe ich eine kleinen Treiber geschrieben, um Musik abzuspielen. Eigentlich sollte es schnell gehen und ich wollte auf etwas fertiges zurückgreifen, aber es stellte sich heraus, dass keine ordentlichen Treiber existieren oder ich nur keine gefunden habe. Die die ich finden konnte hatten keine Optionen, um verschiedene Songs in den Flash abzulegen. Die üblichen Arduino Libs blockierten auch mit Delays den ganzen Prozessor.

Der Anspruch war, dass damit auch Töne auf einem ATTiny25 abgespielt werden können. Also der Flash- und RAM-Verbrauch minimal sein muss.

Da ich nicht besonders musikalisch bin, musste ich erst einmal lernen, wie das mit den Noten und den Pausen überhaupt funktioniert. Da die Lieder leider nur mit Noten vorliegen und nicht in PWM und Wartezeiten, kommt man da leider nicht drum herum. Eine schöne Seite die mir alles schnell erklären konnte findet ihr hier: http://www.musikzeit.info/theorie/

Zum Treiber:

  • zwei Oktaven wählbar (24 Noten)
  • Oktaven-Offset pro Song wählbar
  • Interruptbetrieb, Song läuft automatisch (non-blocking) bis zum Ende
  • Timer bei der dem Overflow-Wert gesetzt werden kann ist nötig (Timer1 bei ATTiny25)
  • eine Note/Pause nur 2 Byte Flash
  • auf 1 MHz optimiert

Wie wird es verwendet?

Anhand von Noten kann ein neuer Song implementiert werden. Dabei wird nur die Note und die Wartezeit in einem Array notiert. Gibt es eine Pause wird einfach die spezielle Note „PAUSE“ hinzugefügt. Für ein Lied das mit einer Note startet und danach eine Pause folgt, würde dies so aussehen:

const uint8_t PROGMEM fuer_elise[] = {
    //note //wait
    //first row
    E2, WAIT_8,
    PAUSE, WAIT_8,

Ist der Song komplett, muss er zur Songliste hinzugefügt werden. Diese liegt aktuell noch im RAM, weil dafür Platz war. Sollte es dort zu eng werden, kann diese natürlich ebenfalls in den Flash gelegt werden.

const uint16_t songlist[] = {
    // pointer to the near flash    //length of track    //play in dur 1 - 6 (1 MHz optimized)
    (uint16_t)fuer_elise,   sizeof(fuer_elise), 3,

Der Aufruf des Songs aus der main loop sieht so aus:

// Play a songe
 playTune(1); //first song

Bevor der Song nicht bis zum Ende abgespielt wurde, kann mit playTune kein Neuer begonnen werden. Es ist aber möglich mit playTune(0); Den aktuellen Song zu stoppen. Natürlich funktioniert das nur im Interrupt-Modus. Per define kann der Treiber auf den blockierenden-Modus umgeschalten werden. Das hat aber eher einen akademischen Hintergrund und keine anderen Vorteile, außer einen zweiten Weg aufzuzeigen.

Wie funktioniert es?

Eigentlich recht einfach… Das versetzen des Timerendwertes verändert die Tonhöhe. Damit ein Duty-Cycle von 50% entsteht, wird immer der entsprechende Compare-Wert hälftig gesetzt. In den Pausen ist der Timer aktiv, aber der Ausgangspin wird zu low gesetzt. Bevor eine neue Note im Interrupt gesetzt wird, wird die Haltezeit errechnet. Da bei jeder Note der Timer unterschiedlich schnell überläuft, muss die Haltezeit entsprechend angepasst werden:

duration = ((uint32_t)pgm_read_word(&waits[pgm_read_byte(((uint8_t*)songlist[play_song-2]) + i)])) * 32 / tone * (1 << ((songlist[play_song] & 0x07) - 1));

Und jetzt in verständlich:

Wartezeit = Wartezeit der Note * 32 (Wartezeit aufweiten = numerische Fehler reduzieren) / Note (= Overflowwert des Timers) * Oktave des Songs (Timer Vorteiler)

Die Formel führt zu einheitlichen Pausenzeiten, obwohl die Periode des Timers stark schwankt. Damit die Noten nicht direkt aneinander gereiht werden, wird zwischen jeder Note noch eine kleine Pause vom Treiber eingefügt.

Ich habe einen anderen Prozessor oder Takt, was ist zu tun?

Eine Portierung auf einen anderen Mikrocontroller sollte kein Problem darstellen. Angepasst werden müssen natürlich die timerspezifischen Aufrufe und die Interruptroutine.

Wird mit einem anderen Prozessortakt gearbeitet, müssen die Wartezeiten und die Oktaventeiler angepasst werden. Die Library ist auf 1 MHz optimiert. Wird der Tiny beispielsweise mit 8 MHz betrieben, sind folgende Einstellungen nötig:

#define DELAY_NOTE_INTERRUPT 40

wird zu

#define DELAY_NOTE_INTERRUPT 5

Außerdem sollte die Oktave des Songs um den Wert drei tiefer gespielt werden. Evtl. muss dazu die maximale Oktavenanzahl von 8 auf 16 erweitert werden.

Quellcode wie immer auf github:

https://github.com/Counterfeiter/ATTiny_Song_Driver

 

Veröffentlicht unter Allgemein | 2 Kommentare