Posts mit dem Label Software werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Software werden angezeigt. Alle Posts anzeigen

Mittwoch, 8. April 2015

Altera FPGA Konfiguration per SPI Flash im Active Serial-Modus

In meinem AmbiController-Projekt verwende ich einen Cyclone IV EP4CE6 FPGA von Altera. Da in diesem Chip kein persistenter Speicher enthalten ist benötigt dieser einen externen Speicherbaustein wie beispielsweise den EPCS16. Dieser ist jedoch recht teuer. Alternativ kann auch ein einfaches serielles SPI Flash mit z.B. 16MBit Speicher verwendet werden. Wie zum Beispiel ein MP25P16, den ich verwende. Dieser ist schaltungstechnisch identisch zum EPCS16 mit dem FPGA verbunden uns wird per SPI angesteuert. Die maximale Frequenz die bei der Kommunikation verwendet werden kann liegt bei 50 MHz.

Für die Konfiguration des FPGA/Flash habe ich bisher immer einen Altera USB-Blaster - China-Clon verwendet, dieser piept zwar hochfrequent wenn man ihn verwendet aber er tut seinen Zweck sonst einwandfrei. Als Software verwende ich Alteras Quartus II bzw. den "Programmer" welcher dort mitgeliefert wird.

Zum Ablauf: Das Flash wird über den FPGA, welcher per JTAG über den USB-Blaster - Clon beschreiben. Hierzu kommt ein "JIC"-File zum Einsatz damit das Design des FPGA persistent im Flash abgelegt wird. Das funktioniert einwandfrei.

Allerdings muss ich dazu sagen, dass ich damit nicht wirklich zufrieden bin. Das Problem ist, dass man in jedem Fall die doch recht unhandliche Quartus II - IDE benötigt. Und das auch in dem Fall um nur kurz ein neues Design auf den Flash übertragen zu können. Wirklich sehr umständlich!

Ich halte mein AmbiController - System jedoch gerne vollkommen frei von Entwicklungsumgebungen, also überdimensional großen Tools wie ein ATmel-Studio oder auch Altera Quartus II. Es ist daher schon immer mein Ziel gewesen die Firmware des Mikrocontrollers als auch das Design des FPGA per USB aktualisieren zu können. Da der Update-Vorgang eines Mikrocontrollers per USB bereits eher Standard ist, gehe ich hierauf nicht groß weiter ein.

Für das Update des FPGA-Flash-Inhaltes ist jedoch bei weitem mehr zutun als am Anfang gedacht...

Zum gewünschten Abauf:
Der Plan war zunächst den AVR XMega per SPI (parallel) zum FPGA anzuschließen und bei Bedarf auf den SPI Flash zuzugreifen. Per USB wird zum Mikrocontroller eine Verbindung aufgebaut, dieser darauf hin in einen Zustand gebracht in dem der Flash zugängig ist (schreibend und lesend) und das Update kann durchgeführt werden.

Leider steckt hier der Teufel im Detail. Prinzipiell ist SPI auf einem Mikrocontroller eine standardisierte Schnittstelle welche - simpel - mittels ATmel Application notes und kurzen Beispielen quasi direkt verwendet bzw. integriert werden kann.

Leider ist es bei SPI jedoch nicht vorgesehen ein MultiMaster-System aufzubauen - bei SPI kann es immer nur einen Master geben welcher mit allen Slaves selektiert kommuniziert. Aufgrund dieser Gegebenheit muss also der FPGA zunächst in einen Zustand gebracht werden in dem er alle SPI-Spezifischen Pins/Leitungen unberührt belässt. Im Aktiven Zustand würde dieser die Signale des AVR grundsätzlich verfälschen, was natürlich nicht erwünscht ist. Mit unberührt ist hier übrigens gemeint das alle Pins des FPGA als hochohmig konfiguriert sind, also keine messbaren Auswirkungen auf die SPI-Leitungen haben.

In meinem Fall habe ich hierzu die Chip-Enable-Leitung (nCE) des FPGA auf High gesetzt, und die nConfig-Leitung des FPGA auf Low. Damit verfällt der FPGA in einen unkonfigurierten Zustand - zum Glück gibt es bei derart schwer zu findenden Antworten auf derartige Probleme noch nette Leute in öffentlichen Foren - in dem alle Pins hochohmigen geschalten sind. Hochohmig bedeutet, dass hier keine Spannungen (durch den FPGA) anliegen und auch kein (messbarer) Strom in irgend eine Richtung an den betreffenden Pins fließt.

Ist der SPI Bus nun vom FPGA losgelöst kann im Mikrocontroller die SPI-Schnittstelle konfiguriert und verwendet werden. Ist hingegen der FPGA aktiv sollten alle SPI-Spezifischen Pins des Mikrocontroller hochohmig gesetzt worden sein, damit diese nicht die Kommunikation des FPGA mit dem Flash stören. Nachdem der Mikrocontroller die SPI-Schnittstelle nicht mehr benötigt sollte diese also wieder deaktivert werden, die Pins hochohmig geschalten und daraufhin der FPGA wieder in den "normalen" Betrieb geschalten werden. Der FPGA lädt sich daraufhin aus dem Flash das neue Design, sofern es aktualisiert wurde, und beginnt seine Arbeit.

Betrachtet man die einzelnen Aufgaben getrennt voneinander gestaltet sich das "Bild" nun deutlich einfacher, aber der Weg bis dahin kann sich ziehen wenn Informationen fehlen oder - wer hätte das gedacht - wenn die Hardware streikt.

Das interessante während der Entwicklung des Verfahrens war also das an meiner AmbiController - Hardware verwendete ATXMega192A3 den Betrieb der SPI-Schnittstelle verweigerte. Letztendlich habe ich drei (3) SPI-Implementierungen getestet, welche alle die interne SPI-Funktionalität verwenden. Und keine einzige hat auch nur ein einziges mal die Clock- oder MOSI-Leitung angesteuert.

Laut einschlägigen Foren ist natürlich dies absolut unmöglich... Vor allem da die Software, welche ich testen durfte von Personen stammte die sie ja erfolgreich seit Jahren auf anderen Controllern verwenden...
Leider hält sich mein Mikrocontroller aber nicht an deren Überzeugung und verweigert dennoch den Dienst. Auch mit gutem zureden war nichts zu bewege. Abhilfe hat mir dann eine Softwareseitige Implementierung einer Master-SPI-Schnittstelle gebracht. Diese ist vermutlich nicht ganz so performant und kompatibel bzw. generisch implementiert, jedoch fehlerfrei und funktionstüchtig.

Ich habe dann einige Zeit mit den Tests der SPI-Kommunikation verbracht, um einen Treiber zu implementieren welcher die Kommandos des SPI-Flashs beinhaltet, wie beispielsweise Pages zu schreiben oder lesen zu können.

Als Gegenstück dazu implementierte ich ein Kommandozeilen-Tool welches in der Lage ist per USB/Serielle Schnittstelle Daten aus dem Flash per Mikrocontroller auszulesen. Die ersten Tests verliefen zufriedenstellend, es kamen Daten aus dem Flash zurück. Der Sieg über Hard- und Software erschien mir sicher. Zumindest zunächst...

Auf den zweiten Blick hin wurden auch Muster, im Vergleich zu den von Quartus II erstellten Image-Dateien sichtbar. Jedoch mit einigen Unterschieden. Zu vielen Unterschieden...

Beispielsweise waren nur die Muster, also die Verteilung der Bytes in den Hexdumps der Dateien ähnlich/gleich. Nicht jedoch die einzelnen Byte. Dies lag daran das in den SOF- und JIC-Dateien - welche Quartus II einem erstellen kann - noch diverse weitere Header und Footer enthalten sind, und in den Flash-Daten selbst nicht mehr enthalten sind.

Weiterhin besteht der Grund für die Unterschieder ALLER Bytes im Flash zu den Quelldaten darin, dass alle Bytes einzeln nochmal bitweise umgekehrt werden (Bsp.: aus 0b0101_1000 wird 0b0001_1010). Mit einem Script, um Bytes in Dateien umzukehren, wurde der Vergleich des Flash-Inhaltes mit den Quelldateien einfacher.

Leider waren diese noch immer nicht identisch. Das Problem war natrlich das Datenformat der im Flash enthaltenen Daten. Es werden für das Konfigurieren eines FPGAs verschiedene Formate verwendet, welche abhängig sind von der verwendeten "Übertragungsform" und dem Flash (jedenfalls sind das die Hauptaussagen aus diversen Foren). Bei mir ist die Übertragungsform "Active Serial" - und damit eine SPI-Schnittstelle zwischen FPGA und einem seriellen Flash, wobei der FPGA der Master ist und sich die Daten aus dem Flash lädt. Der FPGA unterstützt dabei zudem auch eine Kompression der Daten.

Das untersuchen des Flash-Inhaltes nahm also noch kein gutes Ende. Als nächstes verglich ich verschiedene komprimierte und unkomprimierte - von Quartus II erzeugte - Dateien im RBF-Format (Raw-Binary-File) mit dem Flash-Inhalt. Dort hatte ich im Kopf der Dateien größere Unterschiede als im Rest der Dateien, und jede Zweite Page - im Flash - enthielt im letzten der 256 Bytes einer Page den Wert 0x05. Das RB-File enthielt dort weniger einheitliche Werte. Mein Tool zum Zugriff vom PC aus auf den Flash war zu diesem Zeitpukt bereits weiter entwickelt und nun auch in der Lage Daten in den Flash schreiben zu können...

Warum die Daten unterschiedlich waren konnte mir zunächst niemand sagen - wie auch - es lag an meiner Implementierung. Das letzte Byte einer zu schreibenden Page wurde nie korrekt verarbeitet. Diesen Leichtsinnsfehler/Tippfehler korrigiert, und schon waren die Images nahezu identisch. Lediglich in der ersten Page sind aktuell noch Unterschiede enthalten.

Der Grund ist hierfür angeblich, dass RBF nur für parallele Konfgurations-Arten verwendet werden. Der Header der Datei ist also noch unterschiedlich und das Image damit auch nicht lauffähig.

Was ist aber dann die Alternative?

Eine nette Person wies mich darauf hin, dass man mit den beiden Tools "sof2image" und "objcopy" Images erzeugen kann, welche auch beim konfigurieren mit "Active Serial" verwendet werden können. Die Verwendung ist einfach - sofern man keine Scheu vor einer Kommandozeile hat - es wird die mit Quartus II mitgelieferte NIOS2-Kommandozeige benötigt. Dort laufen alle benötigten Tools einwandfrei (bei Quartus II 13.1 auf Win7 Prof. 64bit und mti 14.x auf Win8.1 und Linux) und man kann die Konvertierung einer SOF-Dateirepräsentation des FPGA-Designs in ein Image vornehmen das dem tatsächlich
benötigten Flash-Inhalt entsprechen soll. Die NIOS2-Kommandozeile ist übrigens unter Windows nur eine "DOS-Box" (cmd.exe) in der ein Cygwin läuft.

Hier ein Beispiel für die Konvertierung:

$ sof2flash --input=fpga_design.sof --output=fpga_design.srec --compress --epcs --verbose
$ objcopy -I sreg -O binary fpga_design.sreg fpga_design.epcs_img -v

Vergleicht man nun die erzeugte Datei mit dem tatsächlichen Flash-Inhalt sind aber auch hier weiterhin Unterschiede vorhanden. Um genau zu sein 3 Byte in der ersten Page. Warum ist unklar - zumindest mir - aber interessanterweise funktioniert das erzeugte Image problemlos.

Damit ist für meinen AmbiController eine größere aber umso spannendere Hürde gemeistert, das FPGA Design per USB aktualisieren ohne die vollkommen überladene Quartus II - Umgebung von Altera verwenden zu müssen.

Was die Übertragungs-Geschwindigkeit angeht, mit der die Daten in den SPI Flash geschrieben werden, möchte ich bei Gelegenheit noch Tests durchführen.

Ich jedoch bereits Übertragungsraten von bis zu 60 kByte/s (lesend) vermessen können. Beim schreiben sinkt diese jedoch auf etwa 5,4 kByte/s (Win8.1 + Cygwin) und ca. 18kByte/s unter Linux.

Da die zu schreibenden Datenmengen jedoch sehr klein sind ist diese Geschwindigkeit noch nicht an bzw. über der Grenze zum unerträglichen.


Fossil-SCM to gource converter

Seit nun mehr als 1 1/2 Jahren verwende ich als Source Control Management - System fossil-scm und visualisiere gerne den Verlauf in der Entwicklung per gourceLeider ist gource nicht in der Lage die sogenannte fossil Timeline direkt zu interpretieren, mal davon abgesehen das fossil diese auf verschiedene Arten ausgeben kann. Und nun suche ich seit einigen Monaten nach einer Möglichkeit die Timeline/History durch gource anzeigen lassen zu können, aber ohne erfolg...

Daher habe ich mir nun selbst einen kleinen Parser in Python implementiert, diesen gibt es auf github.

Usage:
# fossil timeline to txt with names changed files
fossil timeline -n 99999 -v > timeline.txt
# convert timeline to gource custom log format and pipe to gource
python fossil_timeline_to_gource.py timeline.txt | gource

Im Repository sind jedoch auch zwei Scripte enthalten welche die Anwendung des Tools exemplarisch abbilden. Zum einen das "test.sh" welches eine ".fossil" - Datei als Parameter erwartet, und lediglich gource aufruft um die Timeline per gource anzeigen zu lassen. Und zum anderen das "covnert.sh" welches zwei Parameter (".fossil" - Datei und der Video-Datei-Name) erwartet und direkt die Timeline direkt in ein per gource visualisiertes MP4-Video konvertiert.

Hier wieder ein Beispiel-Video...




Mittwoch, 12. Oktober 2011

Altera Quartus 11.0 Tools, Ubuntu 11.4, USB-Blaster

Wer mit Ubuntu 11.4 (x86) und der Software Quartus II Version 11.0 Build 157 04/27/2011 SJ Web Edition von Altera arbeitet, um z.B. sein DE0-Nano Board mit "Leben" zu befüllen wird schnell feststellen, dass diese Kombination leider ohne manuellen Eingriff, direkt nach der Installation der Altera Software, nicht funktioniert. Quartus II stürzt direkt nach dem Start mit einem Segfault (zumindest bei mir) ab. Und weder mit dem grafischen Programmer noch mit den Tools auf der Kommandozeile kann auf das DE0-Nano, welches sich am System als USB-Blaster ausgibt, zugegriffen werden. Da ich persönlich lieber auf der Konsole und mit Quartus II (aus vielerlei gründen) nur ungern arbeite, gehe ich hier nur auf die Konfiguration der Kommandozeilen Tools ein, um diese zur korrekten Arbeit zu bringen. Meine Altera Software habe ich mittels dem Altera-Installer unter ~/bin/altera/11.0 installiert.

1. Die ~/.bashrc anpassen

Als erstes muss selbstverständlich der Pfad zu den Binaries der PATH-Variable hinzugefügt werden. Weiterhin benötigen diverse Quartus Tools die Umgebungsvariable QUARTUS_ROOTDIR um korrekt arbeiten zu können, daher habe ich auch diese in meine .bashrc eingefügt.

export PATH=$PATH":~/bin/altera/11.0/quartus/bin:~/bin/altera/11.0/nios2eds/bin:~/bin/altera/11.0/quartus/sopc_builder/bin"

export QUARTUS_ROOTDIR="~/bin/altera/11.0/quartus ~/bin/altera/11.0/nios2eds/sdk_shell"

2. UDEV Zugriffsrecht auf den USB-Blaster einrichten

Ich habe die Datei "/etc/udev/rules.d/40-altera-usbblaster.rules" mit dem folgenden Inhalt angelegt:

BUS=="usb", SYSFS{idVendor}=="09fb", SYSFS{idProduct}=="6001", MODE="0666", SYMLINK+="usbblaster", GROUP="plugdev"

Startet man danach das System neu oder führt einen Reload von UDEV durch, kann auf den USB-Blaster zugegriffen werden. Die Voraussetzung dafür ist natürlich, dass dieser in der Liste der USB-Geräte auch angezeigt wird.

user@host:~$ lsusb -d 09fb:6001
Bus 002 Device 013: ID 09fb:6001 Altera

UDEV kann mit den entsprechenden Rechten mittels service udev reload dazu angewiesen werden die Konfiguration neu zu laden.

3. JTAG Daemon


Dieser Daemon muss laufen, um korrekt auf die JTAG-Chain per USB-Blaster zugreifen zu können. Gestartet wird dieser mit jtagd. Natürlich kann man diesen Daemon auch permanent laufen lassen.

4. Testen der JTAG-Verbindung

Beim Aufruf von jtagconfig wird als Standard die Option --enum ausgeführt. Es werden alle diejenigen Devices angezeigt, die an der JTAG-Chain hinter dem USB-Blaster hängen.

user@host:~$ jtagconfig
1) USB-Blaster [2-1.2.2]
  020F30DD

5. Quartus Programmer testen

Der Quartus Programmer muss selbstverständlich auch auf den USB-Blaster zugreifen können. Das kann mit dem folgenden Aufruf getestet werden.

user@host:~$ quartus_pgm --list

Info: *******************************************************************
Info: Running Quartus II Programmer
    Info: Version 11.0 Build 157 04/27/2011 SJ Web Edition
    Info: Copyright (C) 1991-2011 Altera Corporation. All rights reserved.
    Info: Your use of Altera Corporation's design tools, logic functions
    Info: and other software and tools, and its AMPP partner logic
    Info: functions, and any output files from any of the foregoing
    Info: (including device programming or simulation files), and any
    Info: associated documentation or information are expressly subject
    Info: to the terms and conditions of the Altera Program License
    Info: Subscription Agreement, Altera MegaCore Function License
    Info: Agreement, or other applicable license agreement, including,
    Info: without limitation, that your use is for the sole purpose of
    Info: programming logic devices manufactured by Altera and sold by
    Info: Altera or its authorized distributors.  Please refer to the
    Info: applicable agreement for further details.
    Info: Processing started: Sat Oct  8 18:10:02 2011
Info: Command: quartus_pgm --list
1) USB-Blaster [2-1.2.2]
Info: Quartus II Programmer was successful. 0 errors, 0 warnings
    Info: Peak virtual memory: 82 megabytes
    Info: Processing ended: Sat Oct  8 18:10:02 2011
    Info: Elapsed time: 00:00:00
    Info: Total CPU time (on all processors): 00:00:00

Die Tools quartus_pgm und quartus_pgmw (die grafische Version) sollten nun den USB-Blaster korrekt erkennen und ansteuern können.

Da aber nun das übertragen der synthetisierten Logik nicht genug ist und ich den Build-Vorgang mit einem kurzen Makefile automatisiert habe, möchte ich dass natürlich nicht vorenthalten. Voraussetzung für den korrekten Betrieb sind die oben genannten Einstellungen, dass man sich beim Start im Verzeichnis des Quartus-Projektes befindet und das die Haupt-Datei des Projektes identisch mit dem Projektnamen ist (alles natürlich Case-Sensitive).

#
# Makefile to build FPGA/CPLD synthesis with altera tools.
#
# Licensed under GPL v3.0 (15.10.2011)
# by Kai Lauterbach (klaute at gmail dot com)
#

TARGET=test

MAPPER=quartus_map
MAP_OPTIONS=--read_settings_files=on --write_settings_files=off $(TARGET) -c $(TARGET)

FITTER=quartus_fit
FIT_OPTIONS=--read_settings_files=off --write_settings_files=off $(TARGET) -c $(TARGET)

ASSEMBLER=quartus_asm
ASM_OPTIONS=--read_settings_files=off --write_settings_files=off $(TARGET) -c $(TARGET)

STA=quartus_sta
STA_OPTIONS=$(TARGET) -c $(TARGET)

PROGRAMMER=quartus_pgm
PGM_OPTIONS=-m jtag -c USB-Blaster -o "p;$(TARGET).sof"

compile: clean map fit asm sta

map:
    $(MAPPER) $(MAP_OPTIONS)

fit:
    $(FITTER) $(FIT_OPTIONS)

asm:
    $(ASSEMBLER) $(ASM_OPTIONS)

sta:
    $(STA) $(STA_OPTIONS)

program:
    $(PROGRAMMER) $(PGM_OPTIONS)

clean:
    rm -rf db/ dse/ incremental_db/ sim.do $(TARGET)ig.archive.rpt $(TARGET).asm.rpt $(TARGET).bsf $(TARGET).cdf $(TARGET).done $(TARGET).dse.rpt $(TARGET).fit.rpt $(TARGET).fit.summary $(TARGET).flow.rpt $(TARGET).inc $(TARGET).map.rpt $(TARGET).map.smsg $(TARGET).map.summary $(TARGET).mif_update.rpt $(TARGET).pin $(TARGET).sof $(TARGET).sta.rpt $(TARGET).sta.summary $(TARGET).tis_db_list.ddb $(TARGET)_assignment_defaults.qdf wave.do $(TARGET).archive.rpt



Freitag, 1. Juli 2011

A small and proprietary AVR C-Library to play Wavefiles...

Projekte bei denen Wavedateien abgespielt werden gibt es viele. Bei den meisten ist die dazu implementierte Funktionalität jedoch ein fester Bestandteil der Firmware und dadurch nur oft schwer zu verstehen und oft auch nicht gerade einfach in seine eigenes Projekt zu übernehmen. Zudem ist je nach verwendeten Mikrocontroller die Ausgabemöglichkeit der Audiodaten unterschiedlich, was aber unter Umständen nicht auf den ersten Blick ersichtlich ist. Die erste Alpha-Version der hier vorgestellten Library, welche auf GitHub verfügbar ist, besitzt im Moment die im folgenden beschriebenen Eigenschaften.

Eigenschaften der Library:
  1. Die Library läuft momentan nur auf AVR-Controllern der Mega-Reihe (getestet mit ATMega328p).
  2. Es werden nur Wave-Daten unterstützt die im Flash oder EEPROM abgelegt sind (muss per Preprozessor-Einstellung festgelegt werden).
  3. Die Wave-Daten müssen im PCM-Format (8Bit, Mono, 8kHz Sampling-Rate) und ohne den 44Byte Header im Flash oder EEPPROM abgelegt worden sein.
  4. Die Daten werden per Pulse Width Modulation (8Bit) an den Pins PD5 und PD6 ausgegeben. Die Basisfrequenz liegt hier bei 62,5 kHz.
  5. Timer0 wird dazu verwendet das PWM-Signal (Fast PWM Modus) zu generieren.
  6. Timer2 wird dazu verwendet die Wave-Daten Byte-weise, im Takt der Sampling-Rate, an die beiden Output Compare Register (A/B) des Timer0 zu übergeben. 
Funktionen der Library:
 
Die Library besitzt zudem Funktionen mit denen es möglich ist, die Hard- und Software zu initialisieren und den Abspielvorgang zu starten, stoppen und pausieren. Wenn die Preprozessor-Einstellung für Flash angegeben wurde, kann ein im Repository liegendes Shellscript im tools Verzeichnis dazu verwendet die benötigte C-Datei für die Firmware zu erzeugen (es wird SoX benötigt). Zu beachten ist dabei, dass aufgrund des in C intern verwendeten Datentyps (16Bit signed integer) für den Index von Arrays, die Maximale Anzahl von Samples in der Wave-Datei den maximal möglichen Index von 32767 nicht überschreiten darf. 

Ablauf der Ausgabe:

Der Vorgang zum abspielen gestaltet sich wie folgt. Der Timer0 (8Bit) wird so eingestellt, dass dieser mit einen Vorteiler von 1 (voller CPU-Takt) im nicht invertierenden Fast PWM-Modus läuft und der TOP-Wert für den Zähler des Timers ist dabei der Wert 0xff. Der Counter des Timers läuft also immer von 0 bis 255, was eine Frequenz von 62,5kHz, ergibt.
Ist bei einem Zählvorgang der TOP-Wert erreicht bzw. überschritten, findet ein Überlauf statt, der veranlasst, dass beiden Pins PD5/6 auf High gesetzt werden. Der Counter fängt wieder bei 0 an hoch zu zählen.
Auf Low werden die beiden Pins gesetzt wenn jeweils ein Vergleichswert zum aktuellen Counter-Wert erreicht wird. Diese beiden verwendeten Vergleichswerte sind im Fall des Timer0 die Register OCR0A/B. Durch diesen Vergleichswert kann also die Zeit in 256 Schritten festgelegt werden, wie lange das PWM-Signal, innerhalb einer Periode, auf High oder Low gesetzt ist.

Der zweite Timer (Timer2) ist auch ein 8Bit Timer, der jedoch nich im PWM-Modus läuft. Er wurde so eingestellt, dass er mit einem Prescaler von 8 auf 2MHz läuft und bei einem Vergleichswert von 250 (eingestellt über das Register OCR2A, was exakte 8kHz ergeben und somit die Unterstützte Samplingrate der Wave-Daten von 8kHz entspricht) einen Interrupt auslöst der eine Interruptroutine aufruft. Gleichzeitig wird der Counter des Timer wieder auf 0 gesetzt, der darauf wieder hoch zählt. In der eben genannten Interrupt-Routine wird je nach Konfiguration der Lib, ein Byte nach dem anderen, entweder aus den Wave-Daten aus dem Flash oder EEPROM nachgeladen und in die beiden oben genannten Vergleichsregister OCR0A/B geschrieben. Dies führt dazu, das der Timer0 nachdem nächsten Überlauf, durch erreichen des Counter-Wertes 0x00, das Tastverhältnis direkt ausgibt.

Dieser Wechsel des PWM-Verhältnisses, im Takt der Sampling-Rate, ergibt eine Veränderung der mittleren Ausgangsspannung des PWM-Signals und ist damit (wenn auch recht kantigen) das wiederhergestellte Ausgangssignal aus dem die PCM-Kodierte Wavedatei erzeugt wurde. Dies liegt daran, da bei der Pulse Code Modulation, ein Audiosignal mit einer festen Sampling-Rate (in unserem Fall 8kHz) abgetastet wird. Die Abtasten bedeutet schlicht, dass in einem festgelegten Takt der momentan anliegende Spannungswert an der Datenleitung (in unserem Fall 8Bit-Wert breit) abgefragt wird. Es ergibt sich also eine folge von Werten, aus denen das erfasste Signal wieder rekonstruiert werden kann.

Das ganze oben beschriebene Vorgang ist natürlich nur recht kurz und simpel beschrieben. Er soll lediglich nur einen Überblick über den Vorgang geben. Fehler und Ungenauigkeiten können also enthalten sein und ich bin über jede Anregung oder Korrektur dankbar.

Verwendete Hardware:

Als Hardwarebasis zum testen verwende ich ein Minimexle der Version 3, bei dem ich ein anderes Quarz (16MHz statt 18,432MHz) und einen anderen AVR (ATMega328p statt einem ATMega88) verwende. Durch den AVR mit größerem Flash-Speicher (32kB) sind die weiteren Möglichkeiten in der Firmware wesentlich weniger eingeschränkt als beim Mega88. Zudem besitzt das Minimexle ein Display mehrere Taster und einen Summer. So kann hier die Funktionalität der Lib durch ein simples Benutzerinterface angeboten und auch ohne angeschlossene Kopfhörer etc. die Wave-Daten abgespielt werden können.

Und dadurch, dass beim Minimexle jeder der beiden verwendeten PWM-Kanäle mit einem RC-Tiefpass (erster Ordnung) ausgestattet ist, bevor diese an 3,5" Klinken-Buchsen ausgeführt werden, können einfache Lautsprecher, wie man sie aus PC-Gehäusen als PC-Speaker kennt, oder sehr einfache Kopfhörer sollten ohne Probleme an diese Buchse angeschlossen werden.

Warnhinweis:

Von der Verwendung von aktiven Kopfhörern, Stereoanlagen, Verstärkern oder ähnlichem rate ich jedoch aufgrund der Signaleigenschaften des PWM-Signals dringend ab. Es versteht sich von selbst, dass ich keinerlei Verantwortung für Schäden jeder Art durch Verwendung dieser Software übernehme.

Ausblick:

Für die Zukunft ist angedacht, den Header der Wave-Dateien zur Konfiguration der Timer heranzuziehen, weitere Sampling-Raten zu unterstützen und die Anzahl der verwendeten Timer auf einen zu reduzieren. Zudem soll der zu verwendende Timer auswählbar sein und falls die PWM-Pins, dieses Timers, anderweitig verwendet wurden, ein Software PWM-Modus verfügbar sein der für beliebige Pins, an einem beliebigen Port, betrieben werden kann, usw...

Weitere Links:


Sonntag, 20. März 2011

HackStick Update

Heute geht es um ein Projekt das nun seit mehr als einem Jahr ohne nennenswerten Fortschritt in der Ecke lag, dem "HackStick". In meinem letzten Post habe ich darüber berichtet, dass ich den ursprünglich eingesetzten ATMega8 durch einen ATMega168 ersetzen würde. Das ist längst geschehen und nich mehr aktuell. Nachdem die Ideen für viele neue Features in der Firmware nur so sprudelten, musste unbedingt zunächst ein neuer Mikrocontroller her, um den gestiegenen Anforderungen gerecht zu werden.

Der zuvor verwendete Mega168 war mit seinen 16kB Flash und den vorhandenen 1kB SRAM schon zu jeweils etwa 80% gefüllt. Was aber leider keine weiteren großen Schritte zulies. Abhilfe schafft "der Neue". Ein ATMega328P-PU. Dieser besitzt im Vergleich zu dem vorher verfügbaren Flash, RAM und EEPROM jeweils die doppelte Kapazität. Also 32kB Flash, 2kB SRAM und 1kB EEPROM. Die Bauform und Pinbelegung ist dabei zu der Mega8 Reihe identisch (P-DIP28).

In der Firmware sind jedoch ein paar kleinere Änderungen notwendig gewesen um die USART-Schnittstelle verwenden zu können. Hilfrech ist hierbei die aktuelle UART Library von Peter Fleury. Unter Ubuntu 10.10, mit einem avr-gcc-4.3.5 und der avr-libc-1.6.8-2 musste jedoch das ein oder andere Register, sowie die Interrupt Vektoren, angepasst werden. Leider ist mit dieser Library das Senden von Daten per USASRT (out of the Box) mit dem Mega328p nicht per Interrupt möglich gewesen, was aber an dieser Stelle nicht weiter stört und mich daher auch nicht genötigt hat zu prüfen, warum dieses Feature nicht funktioniert.

Ein weiteres Software-Update hat der Bootloader erfahren, dass ohne Probleme verlief. Lediglich die Fuse-Bits mussten angepasst werden, da ich nicht bei jedem Flashen der Firmware das EEPROM neu beschreiben wollte. Lediglich die Konfigurations-Einstellungen des Bootloaders, sowie eine kleinere Anpassung im Code, mussten durchgeführt werden, um den Bootloader auch aus der eigentlichen Firmware heraus, software-seitig über den AVR internen Watchdog starten zu können. Die vorher vorhandene Möglichkeit den Bootloader zu starten, indem ein Jumper vor dem Einstecken gesetzt wird, bleibt dabei bestehen.

Neben diesen beiden Updates von Firmware-Teilen und der generellen Umstrukturierung, haben sich jedoch noch weitere neue Features ergeben. Die Liste ist lang und daher soll die folgende Liste nur einen Sichpunktartigen Überblick bringen.
  • Setzen, Aanzeigen und Senden aller USB-spezifischen Daten über das TTY. Mit USB-spezifischen Daten sind alle USB Descriptoren, Strings, Vendor-/Device-ID, USB Daten und Sequenzen von zu sendenden USB Daten gemeint.
  • Ein Interpreter mit dem die oben genannten USB Daten-Sequenzen interpretiert und gesendet werden können. Hier stehen, je nach Datenmenge und Headerinformationen, ca. 794 Byte zur verfügung.
  • Es kann festgelegt werden ob auf eingehende Daten reagiert werden soll. Die Reaktion darauf wäre das Starten der Interpretation der aktuellen USB Daten Sequenz.
  • Alle Daten können in das EEPROM gespeichert und daraus geladen werden.
  • Das Startverhalten der Firmware kann in einem im EEPROM abgelegten Konfigurations-Wort festgelegt werden. Es kann hier festgelegt werden, welche Daten beim Start geladen werden sollen, ob die Sequenz-Daten direkt nach dem Start interpretiert werden sollen und ob auf eingehende Daten reagiert werden soll.
  • Eine Online-Hilfe mit Beschreibung aller verfügbaren Kommandos.
  • Wie oben schon erwähnt kann der Bootloader aus der Firmware heraus gestartet werden.

Da die Benutzerfreundlichkeit dieser Features, auf dem TTY, aber leider aufgrund dessen, dass nur unnötig weiterer Speicherplatz im Flash verschwendet werden würde, leidet, habe ich eine kleine GUI geschrieben, um speziell die Sequenzen von USB Daten komfortabler erzeugen und an den HackStick übertragen zu können. Geschrieben ist die Software in Java. Die mit der GUI erzeugten KeyCode-Sequenzen können z.B. bei der Verwendung eines im HackStick festgelegten Hid Keyboard Descriptors, als Tastatureingaben einer Tastatur an den Host gesendet werden. Die Daten werden bei der Erzeugung differentiell in der Sequenz abgelegt. Wer jedoch auf die GUI verzichten möchte kann die im Projekt enthaltene HackStick Klasse auch auf der Kommandozeile zum Übertragen von Dateien verwenden. Zu den Sequenzen muss hierbei gesagt werden, dass der Inhalt der Sequenz-Daten erst in Verbindung mit einem gültigen USB Hid Descriptor für den Host einen Sinn ergeben. So macht es keinen Sinn, KeyCodes an den Host zu senden, wenn der HackStick sich per Hid Maus Descriptor als Maus ausgibt.

Zum Abschluss gibt es, wie so häufig, ein kurzes Video.

 

Der Stick wurde hier so konfiguriert, dass er sich als Hid Keyboard ausgibt und im EEPROM wurden Daten abgelegt, die gesendet werden sobald der Status einer aktivierten NumLock-Taste vom Betriebssystem an die neu angeschlossene Tastatur übergeben wurde. Das ganze kann beliebig oft getriggert werden in dem diese Taste mehrfach betätigt wird.

Edit (2011-05-04 19:46): Bilder der ersten Platinen gibt es hier.

Edit (2011-06-06 22:57): Seit heute gibt es ein GitHub Repository.

Montag, 27. September 2010

LEDMatrix - aktualisierte Firmware

Es ist nun schon einige Zeit vergangen seitdem Mike und ich das Projekt abgeschlossen haben. Leider war der letzte Stand der Firmware noch nicht ganz zufriedenstellend.

Das Problem war zum einen, die Stabilität der USB-Verbindung des Microcontrollers zum Linux-Rechner. Genauer gesagt wurde die USB-Verbindung regelmäßig vom PC aus,resettet wenn zu schnell Daten an den AVR gesendet wurden.

Nach mehreren Tests konnte ich jedoch einen neuen Release der Firmware erstellen, welche zum einen die aktuelle Version des V-USB Projektes beinhaltet und zum anderen einige (kleine aber wichtige) Änderungen die das Timing- und Kommunikations-Verhalten verändern.
Die Verbindung ist nun stabil und die USB-Verbindung wird nicht mehr resettet.
Das zweite, größere Problem war, dass der Microcontroller nur per dazwischen geschaltetem USB-Hub an dem Rechner erkannt wurde, der die Matrix steuern sollte. Jeder andere Linux-PC jedoch hatte mit dem direkten Anschließen des Controllers keine Probleme.
Nachdem wir das Problem mit einem weiteren PC, der auch einen Nvidia Chipsatz besitzt, verifizieren konnten, war das Problem also lokalisiert. Auch diverse Forenbeiträge im OBDEV-Forum ergaben ähnliche Erfahrungen mit Nvidia. Genauer gesagt liegt das Problem beim Timing des Modules im V-USB Treiber für die Verwendung von 16 MHz Quarzen. Manche Chipsätze und deren Treiber kommen damit einfach nicht zurecht. Und da das Debugging in dem Fall (jedenfalls für uns) zu aufwendig werden würde, ersetzen wir demnächst das 16MHz Quarz durch eines mit 12MHz.
Dadurch sollten, laut den Foren, alle Probleme mit der Erkennung  auf Nvidia-Chipsätzen endgültig beseitigt worden sein.

Die neue Firmware kann wie immer hier heruntergeladen werden.
Dem Archiv habe ich auch den aktuellen Schaltplan als PDF beigefügt.

Mittwoch, 10. Februar 2010

USBaspLoader und der GCC-AVR (4.3.3) in Verbindung mit Ubuntu 9.10 (amd64)

Habe ich mich doch vor ein paar Monaten dazu entschlossen mein altes 8.10 Ubuntu (32Bit) durch die neue Ubuntu 9.10 (64 Bit) zu ersetzen. Bisher war ich auch weitgehend überzeugt von der Performance und der Verfügbarkeit der Softwarepakete. Sicher gibt es das eine oder andere Problem, wie zum Beispiel das kein Flash Plugin für den Firefox richtig läuft [solved] oder das manche Programme die libSDL verwenden sich nur mit kill -9 beenden lassen...

Alles in allem aber zu verkraften, Programme die nicht funktionieren werden ggf. aus den Sourcen kompiliert und das Problem ist erledigt.

Aber an manchen Stellen gibt es dann das eine oder andere Tool das einen Stunden seines Lebens kostet. So zum Beispiel der GCC (4.3.3) Compiler aus dem gcc-avr Paket.
Dieser beinhaltet laut diversen einschlägigen Foren eine bessere Optimierung des erzeugten Binary Codes. Optimiert wurde also auch die Option, welche beim übersetzen einer Firmware für Microkontroller normalerweise immer verwendet wird. Die Option -Os. Diese wird an den gcc übergeben um die "kleinstmögliche" Firmware zu generieren. Leider geht der löbliche Optimierungswahn der GCC Entwickler hier ganz klar am Ziel vorbei. Der optimierte Binary-Code ist wesentlich größer als der von älteren gcc-Versionen - tolle Sache...

Mein ATMega168 für den HackStick besitzt 16KB Flash Speicher wovon 2KB für einen Bootloader reserviert werden können. In meinem Fall soll im Bootloader die Firmware des USBaspLoader-Projektes laufen um den HackStick direkt per USB flashen zu können.
Da ist es nicht gerade förderlich, dass der gcc nicht dazu überredet werden kann den, in diesem Fall um 140 Byte(!!!) größeren Binary Code auf die ursprüngliche Größe von 2002 Byte zu verkleinern.

Die Firmware des Bootloaders ist durch das Überschreiten der 2048 verfügbaren Bytes natürlich nicht übertragbar. Zum Glück besitzt man ja nicht nur einen Rechner und so konnte ich die Firmware auf einem anderen kompilieren und übertragen, ohne mir einen älteren GCC installieren zu müssen. Über kurz oder lang kommt man aber bei Ubuntu 9.10 (amd64) nicht drum herum.

Schlussendlich ergab sich aus all dem ein Patch gegen die mittlerweile doch in die Tage gekommenen Version der Firmware des USBaspLoader vom 20.3.2009. Zum einen beinhaltet dieser Patch nun den neuesten Release von V-USB und kleinere Änderungen um den USBaspLoader auf einem ATMega168 lauffähig zu bekommen.

Mittwoch, 27. Januar 2010

Shakes & Fidget Bot

Schneller als gedacht wäre der SFBot also wieder am laufen gewesen... ;)

Dass alle Aktionen des Spielers seit dem Update per HTTP-GET an den Server gesendet wurden war sofort ersichtlich. Und die Session und das Passwort für den Login, sahen auf den ersten Blick einer MD5-Summe doch sehr ähnlich. Glücklicherweise sieht man einer vermeintlichen MD5-Summe aber auch so gut an, dass die Entwickler des Spiels doch tatsächlich das vom Benutzer eingegebenen Passwort erst in UTF-8 umwandeln, bevor die MD5-Summe daraus gebildet wird...

Der Dekompilier-Vorgang einer SWF-Datei dauert ja nur wenige Sekunden, mal davon abgesehen, dass der dabei herauskommende ActionScript-Code recht gut lesbar ist.

Ich habe zwar noch nie den Code einer Methode zur Bildung einer MD5-Summe gesehen, aber da bereits am Anfang der Aufruf stand, der den übergebenen String in UTF-8 wandelte, war das Problem sofort erkannt!

Der Rest war reine Fleißarbeit...

Das Video zeigt die grundlegenden Funktionen des Bot's.



Für alle die jetzt noch fragen was der Bot denn nun alles kann:
Er erledigt Quest's, kämpft in Dungeons und der Arena, meldet sich zu Gilden-Kämpfen an und wenn nichts weiter getan werden kann, schickt er den Held automatisch in die Stadtwache (arbeiten). Das ganze läuft auf jeder Kommandozeile. Benötigt wird nur ein Java Interpreter.

Veröffentlichen werde ich den Quellcode des Bots allerdings aus vielerlei Gründen nicht!
Gegen horrende PayPal Spenden, um meine Arbeit zu unterstützen, habe ich jedoch nichts einzuwenden. ;)


Freitag, 22. Januar 2010

Shakes & Fidget Browsergame

Wer jetzt denkt ich stelle hier ein Browsergame vor, irrt sich. Ganz davor drücken möchte ich mich dennoch nicht. Shakes & Fidget ist eine Online Comic Bilderserie über zwei Figuren die sich humorvoll und planlos ihren Weg durch World of Warcraft kämpfen. Mehr dazu hier. - http://www.shakes-and-fidget.com

Seit einer ganzen Weile gibt es zu dieser Web Comic-Reihe auch ein Browsergame. Da ich aber nicht die Zeit habe das Spiel zu spielen, geht es mir wie auch in vielen anderen Spielen, ich müsste Cheaten, oder mir zumindest einen Weg finden mit selbst den Zeitverlust zu mindern.

Nach ein paar Stunden Entwicklungszeit könnte man ja fast einen Java-Client für die Konsole schreiben, der das Spiel automatisch und wesentlich effizienter spielt als man das als Mensch könnte. Wenn das nicht verboten wäre... ;-)

Das Spiel basiert übrigens auf Flash und kommuniziert(e) plain text über eine unverschlüsselte Socketverbindung mit dem Server.

Vor ein paar Tagen wurde jedoch ein Update des Flash-Clients online gestellt, in dem die Verbindung zum Server auf HTTP umgestellt wurde. Verbessert wurde dadurch nichts merklich, nur das die Bilder noch langsamer geladen werden als vorher.

Aber zum Glück habe ich diesen Bot nicht geschrieben sonst würde das Reverse Engineering schon wieder von vorne losgehen... :D

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern

PowerMgr in der Praxis: PV, Batterie, Kühlung und Hauszustand steuern PowerMgr geht über eine Sammlung von Gerätetreibern hinaus. Der inte...