Kategorie-Archiv: Embedded

Konfigurationsbits im PIC32

Bei meinen ersten Schritten mit dem PIC32 habe ich natürlich mit dem „Hello World“ der embedded Welt begonnen: ein Port Bit wird ein- und ausgeschaltet. Das hat auf Anhieb funktioniert.

Als nächstes stellt sich dann die Frage: wie schnell kann man einen Port ein- und ausschalten. Hier bin ich auf ca. 400 nS gekommen, eigentlich zu langsam für so einen schnellen Prozessor. Unglücklicherweise habe ich das Ergebnis einfach so hingenommen, da es schnell genug für meine Aufgaben war.

Hätte ich mich damals um eine Klärung bemüht, wären mir gestern mehrere Stunden Fehlersuche erspart geblieben. Mein Frequenzzählerprojekt kommt nicht so schnell voran wie erhofft (das liegt zum einen an der verfügbaren Zeit aber noch mehr daran, dass ich mehr lernen muss als ich vorher gedacht hätte) – aber es macht Fortschritte. Mittlerweile haben ich das Anzeigemodul und einen einfachen durchlaufenden Zähler. Als ich gestern meinen Referenztakt von 25 MHz auf den Zähler gegeben habe, hat sich gezeigt, dass der Zähltakt unter einem MHz lief. Der Oszillator war unschuldig, das Oszilloskop hat ordentliche 25 MHz angezeigt.

Die Fehlersuche hat sich etwas mühsam gestaltet, da ich gleich zwei Fehler in der Prozessorkonfiguration hatte. Diese hatte ich einfach aus einem Beispiel übernommen, welches offensichtlich für eine andere Prozessorversion war.

Zum einen wurde der Takt für die externen Komponenten durch den Wert 8 geteilt. Wenn man die kryptischen Kurznamen der Konfiguration verinnerlicht hat, ist das offensichtlich. Mir ist es aber vorher nicht aufgefallen.

Der größere Fehler bestand aber darin, dass die Konfiguration für einen externen 8 MHz Quarzoszillator eingestellt war. Ich habe aber keinen Quarz in meiner Schaltung (der Prozessortakt geht nicht in die Messgenauigkeit ein). Irgendwie lief der Prozessor aber trotzdem, vermutlich blieb er auf einem langsamen internen Oszillator für den Start hängen.

Nachdem ich die Konfiguration in Ordnung gebracht hatte (interner schneller RC Oszillator mit 8 MHz, PLL auf 64 MHz), lief mein Zähler problemlos mit den 25 MHZ (da der Zähler intern synchronisiert wird, ist die Zählertaktrate durch den Prozessortakt beschränkt).

#pragma config FPLLIDIV = DIV_2         // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_16         // PLL Multiplier (16x Multiplier)
#pragma config FPLLODIV = DIV_1         // System PLL Output Clock Divider (PLL Divide by 1)
#pragma config FWDTEN = OFF

#pragma config FNOSC = FRCPLL           // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF            // Secondary Oscillator Enable (Disabled)
#pragma config IESO = OFF               // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)

 

Als nächstes habe ich nun noch mal mein Blinky Programm korrigiert. Jetzt komme ich auf eine Periode von ca. 100 nS für ein Bit Setzen und Zurücksetzen – also ca. 50 nS für eine Portausgabe. Das ist schon viel näher an den erwarteten Werten.

 

Schneller Takt

Frequenzzähler/ Periodenmesser mit einem PIC32 – Teil 4

Als nächstes benötige ich die Zähler für das Eingangssignal. Praktischerweise besitzt der PIC32 neben dem Timer1, den ich für die Anzeige verwende, noch vier weitere 16 Bit Zähler, die sich zu zwei 32 Bit Zählern zusammenschalten lassen. Heute habe ich mich darum gekümmert, die Timer 2 und 3 als 32 Bit Zähler zu verwenden.

In einem ersten Schritt habe ich mich auf die Zusammenschaltung konzentriert und mit dem internen Takt wie beim Timer1 gearbeitet. Das geht relativ einfach und ist nach einem kurzen Blick in das Datenbuch leicht zu erledigen.

    OpenTimer23(T23_ON | T23_SOURCE_INT | T23_PS_1_1, 0xffffffff);

Statt Timer1 wird nun die Kombination aus Timer2 und Timer3 verwendet. Die vordefinierten Hilfsfunktionen und Konstanten sind erfreulicherweise dafür vorbereitet. Der Prescaler wird auf 1 gesetzt, der maximale Timerwert auf volle 32 Bit (die aber nicht komplett benötigen werde).

In der Hauptschleife warte ich nun immer rund eine halbe Sekunde, lese den Timer23 aus und übertrage den aktuellen Wert in den Bildspeicher.

    while(1) {
        int del;
        // wait for 500 milliseconds
        for (del = 0; del < 80000; del++);

        setInt(ReadTimer23());
    };

Das war der einfache Teil, da es im Internet eine Vielzahl von Beispielen gibt, wie man einen Timer mit einem internen Takt verwendet. Für einen Frequenzzähler benötige aber einen Zähler für einen externen Takt. An dieser Stelle habe ich erst mal einen Schreck bekommen, da mir klar wurde, dass ich die Pins für die Ausgangssignale ohne Rücksicht darauf verteilt habe, ob sie eventuell auch von den Timern benötigt werden. Aber ich hatte Glück – das Timer2 Clock Signal, welches auch Eingang für den kombinierten Timer 2 + 3 ist, hat als Eingang einen programmierbaren Pin (PPS). Da ich auf Anhieb kein Beispiel dafür im Internet gefunden habe, musste ich mich jetzt also erst mal mit der Programmierung der Pinbelegung auseinandersetzen. Erfreulicherweise ist es dann aber doch recht einfach. Es gibt zu jedem Eingang eines Funktionsbausteins eine Liste mit den möglichen Pins. Aus dieser Liste muss man einen passenden Pin auswählen, den Mapping-Wert auslesen und in ein Register eintragen. Das war alles – wenn man es erst mal verstanden hat ist es ganz simpel: T3CKRbits.T3CKR = 0;.

void startCounter() {
    OpenTimer23(T23_ON | T23_SOURCE_EXT | T23_PS_1_1, 0xffffffff);
    T3CKRbits.T3CKR = 0; // RA0
}

Wie man im Video sieht, habe ich mittlerweile auch das im Teil 3 beschriebene Übersprechen zwischen den Anzeigestellen in Griff. Das Flackern kommt durch eine Überlagerung der Kamerafrequenz mit der Anzeigefrequenz, es ist im Original nicht sichtbar. Die Wiederholfrequenz liegt bei ca. 90 Hertz.

Aktueller Software Stand:

/* 
 * File:   main.c
 * Author: Matthias Thiele
 *
 * Created on 23. Januar 2015, 21:08
 */

#include <stdio.h>
#include <stdlib.h>
#include <plib.h>

// Configuration Bit settings
// SYSCLK = 80 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 40 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF
// Other options are don't care
//
#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_8
#pragma config OSCIOFNC = OFF // CLKO Output Signal Active on the OSCO disabled
#pragma config JTAGEN = OFF // JTAG Enable (JTAG Disabled)

#define SYS_FREQ             (80000000L)

static int digits[9];
static int dark[9];

// Ermittelt das Port B Bitmuster für einen Wert
// an einer Position im Bildspeicher
int calcPattern(int pos, int value) {
  int hexDigit = (value & 0xf) << 7;
  int position = ((pos & 1) << 11) | ((pos & 0xe) << 12);
  int comma = (pos == 1) ? 0x20 : 0;

  return hexDigit | position | comma;
}

// Schreibt eine Ziffer an eine Position im Bildspeicher
void setDigit(int pos, int value) {
  int pattern = calcPattern(pos, value);
  digits[pos] = pattern;
}

// Schreibt einen Integer Wert in den Bildspeicher
void setInt(int value) {
    int i, j;

    for (i = 8; i >= 0; i--) {
        int part = value % 10;
        setDigit(i, part);

        value = value / 10;
        if (value == 0) {
            // clear leading digits
            for (j = i - 1; j >= 0; j--) {
                setDigit(j, 0xf);
            }
            break;
        }
    }
}

// Zeigt in einer Schleife die 9 Stellen des
// Displays an. Wird aus dem Heartbeat Interrupt
// ca. 1000 mal pro Sekunde aufgerufen.
void displayTick() {
    static int pos = 0;

    // dunkel schalten
    mPORTBWrite(dark[pos]);
    int delay;
    for (delay = 0; delay < 3; delay++);

    // neuen Wert eintragen
    mPORTBWrite(digits[pos]);

    // nächste Stelle ermitteln (round robin)
    pos++;
    if (pos > 8) {
        pos = 0;
    }
}

// Interrupt Service Routine für Timer1
void __ISR(_TIMER_1_VECTOR, ipl2) Timer1Handler(void) {
    displayTick();
    mT1ClearIntFlag();
}

// Initialisert das Display
void initDisplay() {
    int i;
    for (i = 0; i < 9; i++) {
        dark[i] = calcPattern(i, 0xf);
    }
}

// Initialisiert und startet den Heartbeat Timer
void startHeartbeat() {
    OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_256, 4);
    INTEnableSystemMultiVectoredInt();
    ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);
    mT1ClearIntFlag();
}

// Initialisiert und startet die Zähler Timer
void startCounter() {
    OpenTimer23(T23_ON | T23_SOURCE_EXT | T23_PS_1_1, 0xffffffff);
    T3CKRbits.T3CKR = 0; // RA0
}

int main(void)
{
    SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
    mJTAGPortEnable(DEBUG_JTAGPORT_OFF);

    ANSELA = 0;
    ANSELB = 0;
    CM1CON = 0;
    CM2CON = 0;
    CM3CON = 0;
    
    mPORTBSetPinsDigitalOut( 0xfffc );
    mPORTASetPinsDigitalIn( 0x3 );

    initDisplay();
    startHeartbeat();
    startCounter();

    while(1) {
        int del;
        // wait for 500 milliseconds
        for (del = 0; del < 80000; del++);

        setInt(ReadTimer23());
    };
    
}

Weiter zum Teil 5

Frequenzzähler/ Periodenmesser mit einem PIC32 – Teil 3

An diesem Wochenende hatte ich ein paar Stunden Zeit um mich um die Anzeigeroutine zu kümmern. Ziel war es, dass die Anzeige Interruptgesteuert aus einem Bildspeicher heraus erfolgt.

Da die Anzeige 9-stellig ist und ich über eine 10. Stelle noch ein paar externe LEDs ansteuern möchte, brauche ich für eine Wiederholrate von 100 Hertz eine Interruptrate von 1 kHz. Diese Frequenz wird intern über den Timer1 erzeugt.

OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_256, 4);

Die Teilerfaktoren habe ich experimentell ermittelt, sie unterscheiden sich fast um den Faktor 10 von den theoretisch notwendigen Werten. Ich habe den Verdacht, dass mein PIC im Augenblick nicht mit der vollen Taktrate läuft. Das muss ich bei Gelegenheit mal genauer untersuchen, im Augenblick stört es mich aber nicht.

Als nächstes benötige ich eine Interrupt Service Routine (ISR), welche bei jedem Timer-Überlauf aufgerufen wird. Dazu muss die Routine definiert werden und der Timer-Interrupt aktiviert werden.

void __ISR(_TIMER_1_VECTOR, ipl2) Timer1Handler(void) {
    displayTick();
    mT1ClearIntFlag();
}

Die Funktion meldet sich als ISR für den Timer1 an. Bei jedem Aufruf wird die nächste Stelle angezeigt, das ganze immer im Kreis. Am Ende der Routine wird das Interrupt Flag zurückgesetzt damit sie im nächsten Intervall wieder aufgerufen wird. Später wird diese Routine auch noch die Abfrage der Eingabetaster durchführen.

void startHeartbeat() {
    OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_256, 4);
    INTEnableSystemMultiVectoredInt();
    ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);
    mT1ClearIntFlag();
}

Hier nun die komplette Timer-Initialisierung. Nach der Programmierung der Teilerfaktoren wird der Interrupt eingeschaltet und konfiguriert. Das war schon alles. Jetzt wird die Funktion Timer1Handler rund 1000 mal pro Sekunde aufgerufen.

Als nächstes kommt dann die eigentliche Anzeige in der Funktion displayTick(). Sie müsste eigentlich die aktuelle Ziffer aus dem Bildspeicher auslesen, das dafür benötigte Bitmuster für den Ausgabeport ermitteln (jeweils 4 Bit für die Siebensegmentanzeige und den Multiplexer für die Stellenauswahl) und dieses Muster auf den Port B ausgeben. Es ist aber verschenkte Zeit, das Bitmuster 1000 mal pro Sekunde ständig neu zu errechnen, deshalb wird es beim Füllen des Bildspeichers errechnet und statt einfach nur der Ziffer wird das Bitmuster dort abgelegt. Die Ausgaberoutine muss also immer nur die nächste Stelle aus dem Bildspeicher auslesen und auf den Port ausgeben. Die Position des Ausgabecursors wird in der lokalen Variablen pos gespeichert.

static int digits[9];

void displayTick() {
    static int pos = 0;

    mPORTBWrite(digits[pos]);

    pos++;
    if (pos > 8) {
        pos = 0;
    }
}

Nun fehlt noch eine Möglichkeit, den Bildspeicher zu füllen. Als low level Funktion gibt es einen Aufruf, der die Position und einen Wert enthält. Diese Funktion errechnet daraus das Bitmuster für den Port B.

void setDigit(int pos, int value) {
  int hexDigit = (value & 0xf) << 7;
  int position = ((pos & 1) << 11) | ((pos & 0xe) << 12);
  int pattern = hexDigit | position;
  digits[pos] = pattern;
}

Darauf aufbauend gibt es nun eine Funktion, die einen 32 Bit Integer Wert in den Bildspeicher einträgt.

void setInt(int value) {
    int i, j;

    for (i = 8; i >= 0; i–) {
        int part = value % 10;
        setDigit(i, part);

        value = value / 10;
        if (value == 0) {
            // clear leading digits
            for (j = i – 1; j >= 0; j–) {
                setDigit(j, 0xf);
            }
            break;
        }
    }
}

7-Segment AnzeigeBeim Betrachten der Bilder ist mir aufgefallen, dass es ein sichtbares Übersprechen zwischen den einzelnen Stellen gibt. Ich vermute, dass die Abschaltung der Stelle nicht schnell genug ist und jede Stelle deshalb ein paar Mikrosekunden lang noch aktiv ist, während bereits die nächste Stelle angezeigt wird.

[Edit] Das habe ich mir mittlerweile mal genauer angesehen. Man bekommt den Effekt leicht per Software weg, indem man vor dem Wechsel der Stelle den Wert 0xf (alles dunkel) ausgibt und ein paar Mikrosekunden wartet. Ich vermute, dass der PNP Darlington Transistor nicht besonders schnell schaltet. Da er einen großen Vorwiderstand hat, dauert es vermutlich mehrere Mikrosekunden bis er abschaltet.

 
Weiter zum Teil 4

Frequenzzähler/ Periodenmesser mit einem PIC32 – Teil 2

Da ich am Wochenende im Augenblick stark in die Vereinsarbeit (wsb-calw.de) eingebunden bin, geht es mit meinem kleinen Projekt nicht so schnell voran wie gewünscht. Ich habe in dieser Woche aber doch ein paar weitere Schritte geschafft.

Die erste Hürde lag darin, dass ich nicht den kompletten Microstick einbauen wollte. Zum einen ist es zu teuer, für jedes kleine Bastelprojekt ca. 40 EUR auszugeben. Zum anderen wollte ich ein echtes Microcontrollerprojekt haben und nicht einfach nur eine fertige Modulplatine einbauen.

Eigentlich ist es auch nicht kompliziert. Für die Programmierung und das Debugging sind 5 Leitungen vorgesehen: GND und +3.3V, Daten und Takt sowie Reset. Also habe ich den PIC aus dem Microstick herausgenommen und auf meine Platine gesetzt. Die 5 Leitungen habe ich von der Platine mit dem Adaptersockel auf der Unterseite verbunden. Et voià – der PIC wurde von der Entwicklungsumgebung nicht gefunden. An dieser Stelle hätte ich mir eine Stunde Fehlersuche ersparen können, wenn ich mir den Schaltplan des Microstick richtig angesehen hätte. Dort kann man nämlich genau sehen, dass einige Prozessorpins nicht mit dem Adaptersockel verbunden sind. Unter anderem Reset und +3.3V.

Nachdem ich die Verbindung vom Adaptersockel entfernt und direkt in PIC Fassung eingesteckt hatte, lief die Kontaktaufnahme problemlos. Nun hatte ich den Stand, dass ich einen externen PIC32 programmieren und debuggen konnte.

Der nächste Schritt war dann Fleißarbeit: den Siebensegmentdecoder und den 1 aus 16 Demultiplexer vom Steckbrett auf meine Lochrasterplatine versetzen. Das wäre eigentlich einfach gewesen. Unglücklicherweise habe ich für die Verbindungen einen Draht mit einer extrem weichen und wärmeempfindlichen Isolierung verwendet. Und mir dabei gleich einen Kurzschluss zwischen zwei Datenleitungen eingebaut.

Kurzschluss2

Um es noch etwas komplizierter zu machen, habe ich an dem Multiplexer auch noch den Enabled Eingang offen gelassen. Da ein offener CMOS Eingang auf irgend einem Pegel hängt, bekommt man eine extrem unzuverlässige Schaltung. Bei mir blieb das Display dunkel – bis ich mit dem Finger in die Nähe des ICs gekommen bin. Alleine die Nähe hat ausgereicht, dass der Pin mit 50 Hertz Netzfrequenz ein- und ausgeschaltet hat. Wieder ein Abend verloren, bis ich das gefunden hatte.

Der nächste Abend ging dafür drauf, die 9 PNP Transistoren für den Multiplexer auf der Anodenseite einzulöten und Basiswiederständen zu versehen. Dabei hatte ich im Vorfeld den benötigten Platz etwas knapp kalkuliert. Es hat zwar alles gepasst, ist aber etwas gedrängt und schief. Nun ja – später ist es in einem Gehäuse und man sieht es nicht mehr.

Widerstände in zwei Ebenen2

 

Jetzt läuft aber alles und der nächste Schritt besteht darin, eine interruptgesteuerte Anzeigeroutine für den Multiplexer zu schreiben. Der Lötkolben kann ein paar Tage ausruhen.

Langsamer Durchlauf Blick von Oben Blick von Unten

Weiter zum Teil 3

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

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

Linearantrieb mit Schrittmotor

Im klassischen Schreinerbetrieb werden Verbindungen über Eck oft als Fingerzinken ausgeführt. Man kann sie mühsam von Hand sägen, mit einer Schablone und einer Oberfräse ausfräsen oder aber auf auf der Kreissäge erzeugen. Im amerikanischen Umfeld werden dafür gerne dado blades (Nutsägeblätter) verwendet. Das sind mehrere Sägeblätter im Stapel, die in einem Durchlauf gleich einen ganzen Zentimeter Breite raussägen können.

Dado Blade auf Wikipedia

In Deutschland sind die dado blades meines Wissens nach nicht zulässig. Aber man kann es mit etwas mehr Mühe auch mit einem normalen Kreissägeblatt hinbekommen. Es sind dann eben mehrere Durchläufe notwendig, die jeweils um die Breite des Sägeblatts versetzt vorgenommen werden. Die Schwierigkeit liegt dabei in dem korrekten Versatz, denn die Fingerzinken müssen relativ genau gearbeitet werden.

Ich habe mir dabei gedacht, dass sich um den Versatz ein Microcontroller kümmern kann. Man stellt die Breite der Zinken ein und der Controller verschiebt bei jedem Durchgang den Anschlag um den benötigten Betrag. Dieser Versatz ist nicht immer gleich. Bei meiner Säge beträgt die Breite des Sägeblatts 3 Millimeter. Ein 8 Millimeter breiter Spalt wird also durch einen Sägeschnitt erzeugt, gefolgt von zweimal einem Versatz von jeweils 2,5 Millimeter. Danach müssen 8 Millimeter stehen bleiben, der nächste Versatz beträgt also 11 Millimeter. Der Anschlag muss also immer um die Beträge 2,5 – 2,5 – 11 – 2,5 – 2,5 – 11 … Millimeter verschoben werden.

In der Bastelkiste habe ich einen alten Schrittmotor aus einem 5 1/4 Zoll Floppy Disk Laufwerk gefunden. Er hat fünf Anschlüsse, ein gemeinsamer Plus Pol und dann vier versetzte Spulen. Obwohl ich kein Datenblatt dafür habe, konnte ich die Anschlüsse relativ schnell mit einem Ohmmeter ermitteln.

ULN2003Der Anschluss an einen Microcontroller ist recht einfach. Für solche Fälle hat man immer ein paar ULN 2003 rumfliegen. Das sind 8 Darlingtontransistoren mit Vorwiderständen in einem DIL Gehäuse. Da der Schrittmotor aus einem Floppy Laufwerk stammt, gehe ich von einer Betriebsspannung von 12 Volt aus. Tests haben gezeigt, dass ab etwa 8 Volt eine ausreichende Kraft zur Verfügung steht und auch 16 Volt nach längerer Arbeit nicht zu einem heißen Motor führt.

Schrittmotor

Der Microcontroller wird über die USB Leitung mit Spannung versorgt, kann aber auch eine externe Spannungsquelle haben. Der Schrittmotor bezieht seine Versorgung aus einem Labornetzteil (über die grün/ weiße Leitung). Man sieht, dass die komplette Schaltung im Prinzip nur aus einem IC besteht.

Nachdem ich einen laufenden Motor hatte, habe ich zuerst die Schrittzahl für eine volle Umdrehung ermittelt. Das muss nicht übermäßig genau sein, da Schrittmotoren typischerweise eine Schrittzahl von 24, 200 oder 400 besitzen. Ich habe noch keinen Motor gesehen, der 197 Schritte pro Umdrehung im Datenblatt angegeben hat. Ein kleiner Test mit einer Markierung auf der Achse zeigt, dass ich ein Modell mit 200 Schritten habe.

Als nächstes musste ich die Geschwindigkeit des Motors ermitteln. Ein Schrittmotor dreht sich exakt so schnell, wie es über die Schrittfolge vorgegeben ist – zumindest im Normalbetrieb. Wenn man den Motor mechanisch zu stark belastet, verliert er Schritte, d.h. er dreht sich nicht weiter. Wenn man eine langsame Schrittfolge wählt, wird der Vorschub sehr langsam. Die verwendete M6 Gewindestange hat eine Steigung von einem Millimeter pro Umdrehung. Wenn ich 10 cm vorrücken will, sind also 100 Umdrehungen notwendig. Zur Ermittlung der maximalen Schrittrate habe ich die Geschwindigkeit beginnend von 50 Schritten pro Sekunde nach und nach auf 1000 Schritte pro Sekunde erhöht. Wenn die maximale Geschwindigkeit erreicht ist, kann der Motor einen Schritt nicht mehr vollständig ausführen bevor der nächste Schritt kommt. Das führt dazu, dass der Motor mit einem heftigen Brummen stehen bleibt. Von der Maximalgeschwindigkeit habe ich dann noch mal eine ordentliche Portion abgeschnitten. Als Sicherheitsmarge, denn bei dieser Geschwindigkeit ist die Kraft gerade noch ausreichend, um die Gewindestange zu drehen. Aktuell verwende ich maximal 500 Schritte pro Sekunde. Das ergibt 2,5 Umdrehungen pro Sekunde und somit einen Vorschub von nur 2,5 Millimeter pro Sekunde. Da ich jeweils nur kurze Strecken zurücklegen muss, ist das für den Einsatzzweck akzeptabel.

VarsDa die Port-Pins des Microcontrollers nicht in einer Reihe liegen, habe ich sie so verdrahtet, wie es am einfachsten ist. Um zur Schrittgenerierung eine 1 durchzuschieben habe ich ein Array der Länge 4 angelegt, welches dann das jeweilige Port Bit enthält. Es müssen also im Kreis alle vier Werte vorwärts oder rückwärts ausgegeben werden.

Steps

Wenn man bei einem Schrittmotor im Ruhezustand direkt auf volle Geschwindigkeit geht, führt das zu Schrittverlusten, da der Motor nicht so schnell reagieren kann. Im schlimmsten Fall läuft er gar nicht an. Deshalb wird die Geschwindigkeit langsam hochgefahren. Der Abstand vom ersten zum zweiten Schritt beträgt 13 Millisekunden. Er wird bei jedem Schritt um eine Millisekunde verkürzt, bis zur maximalen Geschwindigkeit mit einem Abstand von 2 Millisekunden. Beim Abbremsen passiert das gleiche umgekehrt, die Abstände werden über 10 Stufen langsam verlängert. Wenn weniger als 20 Schritte ausgeführt werden sollen, besteht die Sequenz nur aus einer Teilrampe zum Beschleunigen und Abbremsen.

Move

Die Funktion für den schrittweiten Vorschub wartet auf das nächste Kommando. Wenn es zum nächsten Anschlag weitergehen soll, holt sie sich die nächste Schrittzahl aus dem Feld stepValues über den hochgezählten Index globalStep und führt diese Anzahl von Schritten aus. Die Anzahl wird auch in einem Summenspeicher gemerkt, damit der Linearvorschub über ein zweites Kommando wieder zum Startpunkt zurückfahren kann.
StepGrid

Eine weitere Funktion dient zur Einstellung des Nullpunkts. In diesem Fall fährt der Schrittmotor in eine Richtung, bis diese über einen Tastendruck gewechselt wird.

Erstaunlicherweise gibt es in meiner Bastelkiste einen auffälligen Mangel an Drucktastern. Also musste ich das „User Interface“ auf ein Minimum begrenzen. Auf der Microcontroller Platine gibt es einen User Button – das war alles, was mir zur Verfügung stand.

CheckButtonDer Zustand des User Buttons wird alle 10 Millisekunden geprüft. Zur Entprellung wird ein kurzer Tastendruck gewertet, wenn der Zustand mindestens 50 Millisekunden auf 1 stand.

Wenn er eine Sekunde lang gedrückt wurde, dann wird das als langer Tastendruck gewertet.

Wenn beim Start des Programms der User Button gedrückt ist, geht das Programm in den Null-Einstellungsmodus. In diesem Fall läuft der Schrittmotor in eine Richtung bis der User Button gedrückt wird. Dann wird die Drehrichtung umgeschaltet.

Ist er beim Start nicht gedrückt, geht das Programm in den normalen Vorschubmodus. Bei jedem kurzen Button Klick wandert der Vorschub bis zum nächsten Stopp weiter. Bei einem langen Button Klick geht es zur Startposition zurück.

Was würde ich jetzt anders machen?

Da es sich nur um ein Bastelprojekt handelt, habe ich für den Linearvorschub keine Trapezgewindespindel gekauft sondern einfach eine Gewindestange aus dem Bestand verwendet. Diese hat leider einen deutlichen Schlag, was zu störenden Bewegungen seitlich und nach oben und unten führt. Für den geplanten Einsatzzweck ist das zwar egal, es sieht aber einfach nicht gut aus. Zudem könnte man die Trapezgewindespindel mit einer höheren Steigung kaufen und somit einen schnelleren Vorschub erreichen. Die aktuelle Positionierungsgenauigkeit, von rechnerisch 5 Mikrometer, kann ich ohnehin nicht ausnutzen.

Nachtrag vom 27.12.

Ein kurzer Test zeigt: Prinzipiell funktioniert das System – aber leider nicht mit der Präzision, die ich erhofft hatte. Es ist schwierig, die zu sägenden Teile exakt Senkrecht am Anschlag zu halten. Schon ein kleiner Winkelfehler führt zu unterschiedlich breiten Zinken.

Testschnitt Verleimter Test

 

Eine 4-stellige Siebensegment Anzeige

Von einem anderen Bastelprojekt hatte ich noch 4 Siebensegment Displays übrig. Daraus wollte ich einen 4-stelligen Zähler machen. Da die einzelnen Elemente 25 mm hoch sind, bestehen sie intern aus zwei LEDs pro Balken. Das macht eine Ansteuerung mit üblichen TTL Pegeln etwas unhandlich (Durchlass Spannung laut Datenblatt ca. 4,4 Volt). Zudem sollte die Anzeige in der Helligkeit regulierbar sein, ein einfacher 7447 reicht also nicht aus.

Nach 5342 Sekunden

Zuerst hatte ich gedacht, die Segmente über eine Schieberegisteransteuerung mittels Open Collector bzw. Open Drain anzusprechen. Dazu hatte ich in meiner Bastelkiste aber nichts brauchbares und Schieberegister mit Open Collector sind auch nicht leicht zu bekommen.

Der nächste Gedanke war HCT statt TTL Typen zu verwenden. Die vertragen mehr als 5 Volt Betriebsspannung. Der 74HCT595 ist bis zu 7 Volt zugelassen. Das würde zur Ansteuerung reichen. Die Inputs würden auch bei 7V sicherlich noch zuverlässig mit normalen TTL Pegeln zu schalten sein. Allerdings ist die zusätzliche Versorgungspannung etwas unhandlich.

Direkte AnsteuerungDeshalb habe ich mich dazu entschlossen, die Ansteuerung bei 5 Volt, dafür aber ohne Vorwiderstand auszuführen. Für eine kommerzielle Schaltung sicherlich eine unzulässige Vorgehensweise, da sie so sehr stark auf Bauteil- und Versorgungsspannungs-schwankungen reagiert.

Mein Microcontroller liefert auf der 5 Volt Schiene nur 4,8 Volt. Die LEDs benötigen 4,4 Volt und der Mosfet aus dem Treiber benötigt laut Datenblatt zwischen 0,15 und 0,4 Volt. Alles zusammen gibt einen Strom, der zwar noch unterhalb der zulässigen 20 Milliampere liegt (das Display erreicht nicht die volle Helligkeit) aber doch eine gute Anzeige erzeugt. Und es spart noch den Platz für 32 Widerstände. Die Schaltung wird dadurch deutlich kompakter.

Der 74HTC595 bringt noch einen weiteren Vorteil mit: er hat einen Enabled Eingang, den ich mit einem Pulsweitenmodulationsausgang des Controllers verbinden kann. Darüber kann ich ohne weiteren Hardwareaufwand eine Helligkeitssteuerung aufbauen. Im Testprojekt habe ich  die Steuerung dafür verwendet, bei einem Wechsel der Anzeige nicht einfach hart umzuschalten. Statt dessen wird die alte Anzeige kurz ausgeblendet, der Wert gewechselt und die neue Anzeige eingeblendet (ca. 200 Millisekunden). Es ergibt sich daraus eine altmodische Glühlampen-Anmutung.

Damit das Gesamtmodul möglichst klein bleibt, habe ich die Siebensegmentanzeige auf die eine Seite der Platine gesetzt und die Schieberegister auf die andere Seite. Das war ein wenig fummelig, hat aber doch ganz gut funktioniert.

Rückseite

Jetzt fehlt nur noch die Ansteuerung. Ich habe hierfür ein mbed Modul LPC 1768 verwendet. Dieses setze ich gerne für temporäre Aufbauten zum experimentieren ein. Der Vorteil der mbed Umgebung ist, dass es eine sehr komfortable Software zur Ansteuerung der verschiedenen Ein- und Ausgänge gibt.

MainDas Hauptmodul ist trivial. Es wird pro Anzeigestelle eine Struktur initialisiert, welche die Daten für einen endlichen Automaten enthält. Zudem wird eine Interruptroutine aufgesetzt, die alle 5 Millisekunden läuft und den Automaten weiter schaltet.

Jedes Display „kennt“ die Ziffer der aktuellen Anzeige sowie die Ziffer, welche beim Wechsel nach Aus- und Einblenden angezeigt werden soll.

Damit nur die Stellen dunkler werden, die sich verändern, hat jede Stelle seine eigene Pulsweitenmodulation.

ChangeNach der Initialisierung geht das Hauptprogramm in eine Endlosschleife, die einen Zähler weiter schaltet (setInt) und danach jeweils eine Sekunde lang wartet.

Beim Hochzählen muss für jede Anzeigestelle der neue Wert berechnet werden. Wenn er vom aktuellen Anzeigewert abweicht, wird der neue Wert im Feld nextView gespeichert und der endliche Automat gestart, der die Anzeige langsam Aus- und wieder Einblendet. Diese Funktion ist also nach wenigen Mikrosekunden wieder beendet.

Die Aktualisierung der Anzeige sowie das Aus- und Einblenden findet in der Interruptfunktion statt. Diese wird über eine Timer-Variable alle 5 Millisekunden aufgerufen und prüft für alle vier Anzeigestellen den aktuellen Status.

  • 0: normale Anzeige, keine Änderung des Status-Werts.
  • 56 – 105: Anzeige ausblenden. Die Helligkeit ist bei 105 maximal, bei 55 minimal. Bei jedem Schritt den Status um eins herunter zählen.
  • 55: den Wert „nächste Anzeige“ in die aktuelle Anzeige übernehmen und den Inhalt des Schieberegisters aktualisieren.
  • 50 – 1: Anzeige wieder einblenden. Die Helligkeit ist bei 50 minimal, bei 1 maximal. Bei jedem Schritt den Status weiter um eins herunter zählen.

StateMachineIm normalen Betrieb ist der Status 0, es findet keine weitere Aktion statt. Sobald der Ein-Sekunden Timer den Anzeigewert hochschaltet, wird für jede Displaystelle der neue Wert berechnet und im Feld nextView eingetragen. Der aktuelle Anzeigewert darf noch nicht überschrieben werden, da die Anzeige mit dem alten Wert ja langsam ausgeblendet werden soll.

Jede Stelle, die sich verändert hat, bekommt einen Statuswert 105. Daraufhin zählt der Automat bis 55 herunter und verringert dabei die Helligkeit auf Null.

Bei 55 wird das Schieberegister mit dem neuen Wert geladen und der Automat zählt weiter runter. Ab 50 beginnt er damit, die Helligkeit wieder herauf zu setzen. Bei 0 ist dann wieder die maximale Helligkeit erreicht und der Status bleibt bei 0 stehen.

Leider kommt meine kleine Digitalkamera nicht gut mit den stark schwankenden Helligkeitswerten klar und der Autofocus macht sich selbstständig. Ich richtigen Leben ist das Aus- und Einblenden glatter. Das wird wohl teilweise durch die automatische Helligkeitskorrektur der Kamera weggebügelt. Aber man kann den gewünschten Effekt trotzdem noch erkennen.

 

mbed ST Nucleo F401RE

Ich habe vor einiger Zeit mal mit einem „Netduino“ herumgespielt. Für ein embedded System ist das eine ungewöhnlich komfortable Sache.Es handelt sich dabei um ein ARM System mit dem Anspruch, ähnlich einfach wie ein Arduino zu sein.

Auf des Desktop bin ich kein großer Freund vom Visual Studio. Im ebedded Bereich ist das aber mit weitem Abstand die komfortabelste und problemloseste Umgebung die ich kenne. Software installieren, Netduino an den USB Port anschließen und los geht’s. Inclusive eines komfortablen deployments und debuggers.

Mich persönlich hat jedoch der Overhead der .Net Umgebung gestört. Zu diesem Zeitpunkt gab es noch keinen JIT Compiler für die ebedded Variante (hat sich das geändert?). Ein einfaches Port-Bit setzen hat etwa 5,5 Mikrosekunden gedauert. Zugegeben, es waren ausgesprochen komfortable logische Port-Pins mit vielen Möglichkeiten. Aber es war einfach zu langsam. Über 350 Takte nur um einen Port zu setzen, das ist als würde man seine Pommes Frittes mit dem Lastwagen abholen. Damit konnte ich noch nicht mal einen einfachen digitalen Dreh-Encoder ohne Schrittverluste abfragen. Deshalb habe ich dieses schöne Projekt nicht weiter verfolgt.

Vor einem Jahr bin ich auf die mbed Umgebung gestoßen. Sie erlaubt ebenfalls einen extrem einfachen Einstieg. Einfach ein online Konto einrichten und die einfache aber ausreichende Entwicklungsumgebung läuft im Browser. Der Compile Button löst einen Browser Download der Binärdatei aus, welche man direkt in dem Controller speichern kann, der sich über den USB Port als Massenspeicher anmeldet.

http://developer.mbed.org/platforms/ST-Nucleo-F401RE/

Der Source Code wird in C++ erstellt – kein Problem, ich habe über 20 Jahre mit C und C++ gearbeitet. Als routinemäßiger Java Mann lag mir das C# vom Netduino aber eher. Die Hoffnung war, dass der C++ Compiler besseren Code erzeugt.

Also einfach mal ein kleines Programm geschrieben – Port auf 1 gesetzt, zurück auf 0 und das ganze in eine Schleife gepackt und das Oszilloskop dran gehangen. Hier komme ich nun auf Zeiten von 260 Nanosekunden zum setzen und zurücksetzen. Die Schleife selber erzeugt übrigens keine messbare Verzögerung.

mbed Bit Setzen und Zurücksetzen

Ein kurzer Blick in das Datenblatt – der F401RE hat einen Takt von 84 MHz – dann sind das ca. 22 Takte. Das ist ein sehr viel besserer Wert. Ein schöner Nebeneffekt: ein Board kostet gerade mal 8 Euro. Dafür bekommt man einen 32 Bit ARM Prozessor mit 84 MHz Takt, ordentlich RAM und Flash Speicher sowie einen 12 Bit A/D Wandler.

Nucleo-F401RE

Der Nachteil: der einfache Einstieg über den Browser ist gleichzeitig die größte Beschränkung für die Entwicklung. Debugging ist nicht. Ich habe verschiedene Entwicklungsumgebungen ausprobiert und habe für Debugging-Zwecke eine freie Version von Keil behalten. Diese ist aber in keiner Weise mit der Visual Studio Entwicklung vergleichbar. Schade – aber man kann nicht alles haben.

Jetzt habe ich schon mal eine schöne Lösung, ich muss mir nur noch ein Problem dafür suchen…