Archiv für den Monat: Januar 2015

Frequenzzähler/ Periodenmesser mit einem PIC32 – Teil 1

Im Internet hatte ich vor ein paar Wochen ein Verfahren gefunden, wie man einen Frequenzzähler mit guter Genauigkeit und Messauflösung aufbauen kann. Das Original wurde mit einem AVR Prozessor aufgebaut. Da ich ein PIC32 Projekt durchführen wollte, habe ich diesen Prozessor gewählt, auch wenn ein einfacheres Modell gereicht hätte.

Hier findet man das Originalprojekt, welches sehr gut beschrieben ist und mir wirklich gut gefallen hat.

Siebensegmentanzeige

Bei ebay konnte ich für wenige Euro 9-stellige blaue Siebensegment Displays erwerben. Da mein PIC32 Modell nicht gerade üppig mit Pins bestückt ist, habe ich einen normalen Siebensegment Decoder 7447 verwendet. Das hat auch den angenehmen Vorteil, dass ich gleich eine Open Collector Ansteuerung für die LEDs habe. Den Dezimalpunkt kann ich im Augenblick noch nicht ansteuern, dafür werde ich noch ein Port-Pin spendieren müssen.

Zum Multiplexen der einzelnen Stellen habe ich einen 1 aus 16 Decoder 74154 verwendet. Ich hatte auch überlegt, einen 1 aus 8 Decoder (74138) zu verwenden und die neunte Stelle dann direkt anzusteuern. Das hätte die Schaltung aber umfangreicher gemacht und bringt kaum eine Einsparung. Dann sind eben 7 Schaltzustände ungenutzt. Das kann ich später dazu verwenden um zusätzliche LEDs zur Statusanzeige anzusteuern.

Da ich die Segmente mit mindestens 30 mA ansteuern möchte (laut Datenblatt sind 30 mA erlaubt, deshalb wird das Display es auch überleben, wenn der Multiplexer mal stehen bleibt), kann ich die Stellenumschaltung nicht direkt vom IC aus ansteuern. Es müssen bei der Anzeige der Ziffer 8 ca. 240 Milliampere geliefert werden. Also erfolgt die Ansteuerung über einen PNP Darlington Transistor der mit dem Emitter an Plus liegt. Der Decoder zieht den ausgewählten Kanal freundlicherweise auf 0 – genau passend zur Ansteuerung des Transistors, natürlich mit einem Vorwiderstand. Vermutlich hätte hier statt eines Darlingtons auch ein normaler PNP Transistor gereicht.

Die TTL ICs betreibe ich mit den vorgeschriebenen 5 Volt, den PIC mit 3,3 Volt. Der High Level des PIC hat aber auch bei nur 3,3 Volt einen ausreichend hohen Pegel um von den TTL ICs als High erkannt zu werden.

Für den Prototypen auf dem Steckbrett habe ich nur 3 Stellen verkabelt. Der nächste Schritt besteht darin, das Ganze dann vollständig auf einer Platine aufzubauen. Sobald die Anzeige dann steht, geht es an den Zählerteil.

Zähler 1

Etwas zum Nörgeln habe ich zum Schluss aber noch: die Port-Pin Verteilung bei den 28 Pin PIC32 ist übel. Vom Port A stehen prinzipiell die ersten 5 Bit zur Verfügung – die Einschränkung deshalb, weil ich nur PA0 und PA1 tatsächlich zu einer Ausgabe überreden konnte. PA2 und PA3 gehören scheinbar dem Programmieradapter. Die Verwendbarkeit von PA4 habe ich nicht überprüft.

Beim Port B ist es auch nicht toll. Er ist auf den ersten Blick vollständig – aber nein: die Bits 6 und 12 fehlen ganz. Zwei weitere Bits sind durch den Oszillator belegt und ich habe noch nicht herausgefunden, wie man sie als Ausgang verwenden kann. Da ist es schon mühsam, vier zusammenhängende Bits als Bus zu finden. Das hätte man vielleicht auch sinnvoller aufteilen können.

Weiter zum Teil 2

Programmier-Un-tugenden, die man vermeiden sollte

Gestern ist mir mal wieder unschöner Programm-Code über den Weg gelaufen. Das hat mich dazu animiert, mal die häufigsten Fehler aufzulisten, die ich immer mal wieder sehe und über die ich mich dauerhaft ärgern kann.

Dabei geht es mir noch nicht mal um irgendwelche abstrakten Programmiermodelle oder best practices im Architekturbereich. Es geht um kurze, alltäglich Codestücke, die man eigentlich nicht falsch machen kann. Und doch wird es gerne falsch gemacht. Es geht auch nicht um Syntaxfehler, die filtert der Compiler raus. Sondern einfach nur um schlechten Code, der irgendwie funktioniert.

1. Unklare Vorstellungen über boolsche Werte

Wenn ich solche Abschnitte sehe, stellen sich mir die Nackenhaare auf:

boolean isEnabled = myButton.getEnabled();

if (isEnabled == true) { ...

Die Variable isEnabled enthält einen boolschen Wert, die IF-Entscheidung erwartet einen. Warum dann noch diesen zusätzlichen Vergleich dazu packen. Damit sich der Compiler auch wirklich sicher ist, dass der Wert true ist? Und dann könnte man konsequenterweise doch auch „if ((isEnabled == true) != false)“ schreiben.

Mir signalisiert so eine Vorgehensweise, dass der Entwickler nur eine vage Vorstellung von boolschen Werten und ihrer Verwendung besitzt.

2. Überflüssige Kontrollstrukturen

Dieses Beispiel geht in die gleiche Richtung wie Beispiel 1.

boolean isEnabled = myButton.getEnabled();

if (isEnabled) {

  otherButton.setEnabled(true);

} else {

  otherButton.setEnabled(false);

}

Hier wird ohne nachvollziehbaren Grund eine komplette Kontrollstruktur aufgebaut. Dabei kann ich mich gar nicht über die verschenken Nanosekunden ärgern. Aber jeder andere Entwickler erwartet hier, dass etwas passiert, was schwergewichtiger ist als eine einfache Zuweisung: „otherButton.setEnabled(isEnabled)“.

Leider kommt dieser Fehler in der Praxis immer wieder vor. Auch hier liegt vermutlich oft einfach ein Defizit im Bereich „mal darüber nachdenken, was ich gerade mache“ vor.

3. Verdrehte Ausdrücke

Eines meiner Lieblingsaufreger, besonders gern von alten C Programmierern gemacht:

if ( 7 == anzahlWochentage) ...

Das liest sich einfach schlecht – Obi-Wan Kenobi Grammatik. Wenn man den Ausdruck umgangssprachlich formulieren würde, würde man sagen „Wenn die Anzahl der Wochentage gleich 7 ist“ und keinenfalls „Wenn 7 die Anzahl der Wochentage ist“. Auch wenn der Inhalt der gleiche ist, stolpert man über die falsche Reihenfolge, der Gedankenfluss wird gestört, die Aufmerksamkeit ist beeinträchtigt.

Die Herkunft dieses Anti-Patterns ist klar. Uralte C Compiler (älter als 30 Jahre), haben die Anwender leichtfüßig in Fehler der Art „if (anzahlWochentage = 7)…“ laufen lassen. Durch das vergessene zweite Gleichheitszeichen wird aus dem Vergleich eine Zuweisung. In der umgedrehten Schreibweise führt das zu einem Compilerfehler, da ein konstanter Wert nicht als Left-Value verwendet werden kann. Aber auch vor 30 Jahren gab es schon „lint“ für solche Probleme. Alle modernen Compiler werfen hier deutliche Warnings aus, so dass man diesen Fehler eigentlich nicht mehr machen kann.

Ein Entwickler, der sich dieser Schreibweise bemächtigt, löst bei mir schnell den Verdacht aus, dass er sich nicht um seine Warnings kümmert. Oder, dass er so viele Warnings hat, dass er sie gar nicht mehr kontrollieren kann. Beides ist schlecht, der Programmierer bewegt sich Haarscharf an der Grenze zum Chaos.

4. Magic Numbers

Die Verwendung von symbolischen Konstanten statt Zahlen im Quellcode ist mittlerweile fast überall Standard. In vielen Firmen gibt es Style Guides, die die Verwendung von Magic Numbers ausdrücklich verbieten.

Der Nutzen von Konstanten liegt auf der Hand. Wenn ich fünf Produktgruppen habe und im Programmcode alle Schleifen mit der Ziffer 5 laufen lasse, habe ich bei einer Erweiterung auf 6 Gruppen massiven Aufwand. Man kann ja nicht einfach per Suchen und Ersetzen alle 5 gegen eine 6 austauschen. Statt dessen muss man sich jede Verwendung genau darauf hin ansehen, ob die Zahl der Gruppen gemeint ist. Zudem gibt es weitere Verwendungen, der Index der letzten Gruppe beträgt 4 und nicht 5. Darauf muss man also auch achten.

Übel wird es, wenn ein Programmierer zwar den Wortlaut der Regel befolgt aber den Sinn nicht verstanden hat (oder nicht verstehen will). Dann kommen solche Konstruktionen vor:

const FIVE = 5;

...

for (var group = 0; group < FIVE; group++) ...

Der Wortlaut der Regel wurde befolgt, im Programmcode selber gibt es keine Magic Numbers. Aber das Ziel wurde verfehlt. Ich sehe der FIVE in der for Schleife nicht an, was für einen Zweck sie hat. Besonders übel wird es, wenn sich die Zahl der Gruppen auf 6 erhöht:

const FIVE = 6;

So eine Vorgehensweise kann man nur begrenzt mit Unfähigkeit begründen. Das grenzt schon an Sabotage.

5. Unsinnige Kommentare

Vernünftige Kommentare zu erstellen, ist nicht unbedingt einfach. In manchen Betrieben gibt es eine Festlegung, was kommentiert werden muss. Bei uns ist es z.B. so, dass alle public Methoden mit einem JavaDoc Header versehen werden müssen. Kommentare innerhalb einer Funktion sind aber kaum über einen Style Guide definierbar. Wenn man dann einfach einen bestimmten Prozentsatz von Kommentarzeilen fordert, entstehen solche Konstruktionen:

customers++;  // customer wird eins hochgezählt

Ein unglaublich blöder Kommentar, der genau das wiederholt, was der Programmcode ganz offensichtlich ausführt. Solche Kommentare sind nicht nur nutzlos. Sie sind sogar schädlich. Spätestens dann, wenn sich der Programmcode mal ändert und der nutzlose Kommentar nicht angepasst wird. Dann habe ich einen Widerspruch im Quellcode der schwere Irrtümer auslösen kann.

Kommentare sollten im Normalfall NICHT beschreiben, was passiert. Das wird durch den Programmcode am Besten beschrieben. Und wenn der schwer verständlich ist, dann sollte man sich lieber Gedanken über eine bessere Schreibweise statt über einen Kommentar machen.

Kommentare sollten beschreiben WARUM etwas passiert. Denn dieser Teil ist nicht aus dem Code abzuleiten. Vielleicht aus dem Kontext. Oder aus dem Pflichtenheft (liegt das fünf Jahre später noch in einer aktualisierten Form vor?).

Erste Schritte mit dem PIC32

Gestern ist die neue Hardware gekommen. Auch hier habe ich als erstes mal Blinky ausprobiert.

Die erste Hürde lag in den Projekteinstellungen. Dort kann man den Microstick direkt auswählen. Dann wird er aber nicht erkannt. Statt dessen muss man „Starter Kits (PKOB)“ auswählen. Zum Glück wird man durch den grünen Punkt in die richtige Richtung geleitet.
ToolSelection

Nachtrag: wer lesen kann, ist im Vorteil. Die Selektion heißt MICROSTICK – ich habe aber einen Microstick II, das Nachfolgemodell.

 

PIC32Timing3

Ein erster Test mit dem Oszilloskop zeigt nur mittelprächtige Werte. Knapp 400 nS für ein Bit setzen oder zurücksetzen, das ist nicht toll für 12,5 nS Taktrate. Ich komme auf 30 Takte. Vermutlich ist das dem Compiler geschuldet, der in der kostenlosen Version keine Optimierungen bietet. Falls ich damit Probleme bekomme, werde ich es mal mit Assembler versuchen. Im Augenblick werde ich erst mal die Hardware erforschen.

PIC32Timing3ASMDer Neugierde halber habe ich mir doch mal den erzeugten Assembler Code angesehen. In den Projekteigenschaften kann man einstellen, dass die temporären Dateien nicht gelöscht werden. So ganz klar ist mir noch nicht, wo da die 30 Takte bleiben, das werde ich in den nächsten Tagen mal genauer untersuchen.

Nachtrag vom 22. Februar 2015

Ich habe dem Prozessor unrecht getan. Durch eine Konfigurationsfehler lief er nur mit etwa einem Achtel des möglichen Takts. In der verbesserten Konfiguration komme ich auf etwa 50 nS.

Link zum neuen Test

Wenn ich das zu diesem Zeitpunkt genauer untersucht hätte, wären mir einige Probleme in dem Folgeprojekt erspart geblieben.

Ernüchterung bei mbed

Nachdem ich mich über die Feiertage etwas intensiver mit der mbed Umgebung beschäftigt habe, ist meine erste Begeisterung etwas gedämpft worden. Solange man sich innerhalb des mbed Frameworks bewegt, ist alles prima. Mit wenigen C Statements kann man sich schöne Sachen programmieren.

Hässlich wird es, sobald man etwas braucht, was nicht für das Framework abgedeckt wird und man sich in Tiefen der ARM Hardware begeben muss. Auslöser bei mir war eine Anleitung im Internet zum Bau eines Frequenzzählers. Mein nucleo Board hat fast alles, um diesen Vorschlag, der auf AVR Microcontrollern basiert, mit minimalen Hardware Aufwand zu realisieren. Da das mbed Framework von Haus aus keine Counter mit externen Quellen unterstützt, habe ich erforscht, wie das funktioniert. Und da bin ich als Hobby Bastler dann doch etwas überfordert. Damit sich kein ARM Fan auf die Füße getreten fühlt: die Möglichkeiten sind gigantisch. Aber das ist auch genau das Problem: die Dokumentation ist schlecht. Und jeder Chip Hersteller macht es anders. Deshalb ist auch das Internet keine Hilfe. Eine Lösung, die jemand für einen anderen Chip gefunden hat, hilft mir nicht weiter.

TargetsAls nächsten Anlaufpunkt habe ich mir dann das mbed Framework angesehen. Eine typische Entwickler-Strategie: Lernen durch forschen, wie es andere machen. Sobald man auf die HAL Ebene kommt (Hardware Abstraction Layer), beginnt das Elend. Die Funktionen sind für jeden Hersteller anders implementiert (was noch nachvollziehbar wäre – aber nicht schön) und noch schlimmer – innerhalb der ST Familie ist auch noch jeder Chip individuell implementiert.

Da ich noch andere Hobbies habe, bin ich nicht bereit, jetzt wochenlang in die Niederungen der Hardwareprogrammierung für den F401 Chip einzusteigen. Nur um es beim Umstieg auf einen anderen Chip wieder neu anzufangen. Hier verrennt man sich in Nischen. Für professionelle Entwickler ist es sicher schön, für jedes Problem eine Lösung zu haben. Für mich als Bastler ist es leider eine Sackgasse.

Da für mich das Entdecken und Ausprobieren ohnehin eher im Vordergrund steht als das Realisieren, habe ich überlegt, welche anderen Möglichkeiten zur Verfügung stehen. Es sollten günstige Entwicklungsboards zur Verfügung stehen und zumindest theoretisch die Möglichkeit bestehen, auch eigene Boards zu entwickeln. Und das wichtigste: es sollte eine vernünftige Entwicklungsumgebung verfügbar sein.

Atmel AVR

Die 8 Bit Atmel-AVR Familie ist in Maker-Kreisen sehr stark verbreitet. Besonders die Arduino Entwicklung hat völlig neue Anwender Kreise erschlossen. Vor 15 Jahren habe ich schon  mal damit experimentiert. Auch das Frequenzzähler Projekt ist mit einem AVR Prozessor realisiert. Allerdings wollte ich es nicht einfach nachbauen sondern auch erweitern. Dafür habe ich in der Prozessorliste auch ein geeignetes Exemplar gefunden – kann es aber nicht in Einzelstückzahlen kaufen. Bei den 8 Bit Prozessoren stößt man Allgemein schnell an Grenzen, vor allem der RAM Bereich ist bei den meisten (allen?) Exemplaren sehr begrenzt.

Es gibt auch eine 32 Bit Variante – die wird aber scheinbar von Bastlern nur wenig verwendet. In Folge gibt es auch nicht so viel Hilfe und Tutorials. Und man kann auch nur begrenzt viele Modelle kaufen.

TI MSP 430

Dieser 16 Bit Prozessor war von Anfang an auf niedrigen Energieverbrauch optimiert. Mir gefällt die Architektur (einfach und überschaubar) und es gibt auch eine brauchbare Entwicklungsumgebung. Auch damit hatte ich vor 10 Jahren schon mal experimentiert und auch hier gibt das Datenblatt für mein geplantes Projekt geeignete Modell her. Aber auch hier hapert es mit dem Kaufen. Es gibt viele Varianten, aber gerade die interessanten Modelle sind nicht für den Bastler erhältlich.

Microchip PIC

Eigentlich gefällt mir dieser Prozessor von der Architektur her nicht. Aber er hat ein große Verbreitung und für den Bastler gibt es viele Modelle zu kaufen. Deshalb habe ich mir diese Modellreihe mal angesehen.

Die PIC Familie besteht nicht nur aus den (hässlichen) 8 Bit Varianten. Es gibt auch 16 Bit und 32 Bit Prozessoren. Beim Studium der Datenblätter ist mir aufgefallen, dass die 32 Bit Varianten PIC32 auf dem MIPS Prozessor basieren. Damit war mein Interesse geweckt. Als Bastler kann ich viele verschiedene Modelle kaufen und es gibt sie auch im DIL Gehäuse, ideal für einen Steckbrett-Aufbau. Eine eigene Platine kann mit minimaler externer Beschaltung realisiert werden (das war auch beim AVR toll).

Die Entwicklungsumgebung kann man sich bei Microchip herunterladen und sie kam mir gleich bekannt vor – sie basiert auf Netbeans (eine Java und C++ Entwicklungsumgebung). Praktischerweise gibt es sie auch für Linux. Auch wenn ich im Augenblick mit Windows 8.1 arbeite, wechsele ich hin und wieder zwischen Ubuntu und Windows. Dann ist es schön, wenn die Entwicklungsumgebung in beiden Systemen verfügbar ist.

Die Installation ist einfach und ohne Überraschungen. Es kommt auch ein Simulator mit, also habe ich gleich mal „Blinky“ – das HelloWorld der Embedded Welt ausprobiert und erweitert. Alles hat auf anhieb funktioniert und man mussten sich nicht mit unerwarteten Problemen rumschlagen. Die Hardware ist bestellt, kommt aber erst in ein paar Tagen. Dann werde ich weiter berichten. Ich wollte mich schon lange mal mit der MIPS Welt auseinandersetzen.

Simulator