STM32F1 Paintboard

#Einleitung

Der STM32 als solches wurde ja schon bei STM -> F1 Einstieg vorgestellt.
Der bei diesem Entwicklungsboard verwendete Mikrocontroller ist ebenfalls ein STM32F103 mit 64Pins.
Das Board ist bei Ebay für rund 30 Euro zu bekommen und lässt sich recht vielseitig einsetzen.

#MiniSTM32 V3.0

Board (LCD abgezogen)|noresize
  • µC STM32F103RBT6 (128kB Flash, 20KB RAM, 72MHz)
  • 2 Quarze: 8 Mhz (für HSE) und 32 KHz (für RTC)
  • 2.8" LCD 320x240 (Touch-Chip: ADS7843 LCD-Chip: ILI9325)
  • 2 LEDs in Rot (4 insgesamt, davon 2 für Status)
  • 2 Tasten (4 insgesamt, davon 1x Reset und 1x Bootloader)
  • SD-Karten Slot (SPI-Modus)
  • JTAG Anschluss
  • USB-RS232 Wandler (verbunden mit Uart1 am µC)
  • jeder µC GPIO-Pin über Stiftleiste nach außen geführt

Zur Programmierung nutze ich die Keil IDE µVision 4 und den ST-Link über JTAG.

#Beschreibung

Bei dem hier vorgestellten Beispiel, ging es mir nicht direkt um einen sinnvollen Einsatz. Vielmehr will ich ein paar der Möglichkeiten dieses Boards aufzeigen.
Folgende Codevorlagen wurden verwendet:

Touch Screeen
Das Display hat einen resistiven Touchscreen, welcher direkt mit dem Auslesechip auf der LCD-Modul-Rückseite platziert ist. Der Auslesechip hat 4 Analogeingänge (x+,x-,y+,y-) und wird über den SPI Bus ausgelesen.

SPI-Bus
Der SPI-Bus ist ein taktgesteuertes Datenübertragungssystem, welcher gern und oft verwendet wird. Die Taktrate entscheidet darüber, wie schnell die Daten gesendet werden und dieser Takt darf bis in den MHz Bereich gehen. Außerdem werden hier die Geräte (Slaves) meistens nicht mit einer Adresse, sondern mit einem Aktiv-Pin (CE -> Chip Enable oder NSS -> Negativ Slave Select) aktiviert. Diese Pins gelten für gewöhnlich als aktiv, wenn sie Low sind. Wenn genügend Pins vorhanden sind, ließen sich auch 1000 Sensoren/Displays/Speicher oder sonst was an einem SPI Bus betreiben.
Auf diesem Board sind 2 Slaves (Touchcontroller und SD-Karte) ein weiterer ist optional (SPI-Flash auf dem LCD-Modul), dort ist also nur eine freie Fläche, man kann sich einen solchen Chip aber besorgen, wenn man ihn verwenden will (sollte ein SOIC-8 sein... einfach mal googeln "spi flash SOIC8").

RTC
Die Real Time Clock nutzt einen extra Quarz auf dem Board und erzeugt je nach Einstellung bis zu 10mS Interrupts. Ich hab sie hier auf 1000mS gestellt und lasse im Interrupt die LED3 umschalten. Sie ist also alle 2 Sec für eine Sec aktiv. Außerdem hat die RTC einen internen Zähler, der bei jedem Takt um eins nach oben geht. Der Zählerstand wird auf dem Display nach "T: " ausgegeben und zeigt die Betriebssekunden des STM32.

Low-Power
Die Taste Key2 schickt das Board in den Stop-Mode. Vorher wird noch die USB Verbindung abgeschaltet und der LCD-Controller bekommt ein Shutdown Befehl. Außerdem wird das Hintergrundlicht abgeschaltet.
Das Board sieht dann so aus, als wäre es ohne Spannungsversorgung.
Die Taste Key1 ist als unter anderem als Interrupt konfiguriert, welcher das Board wieder aktiviert. Mit Key1 und Key2 kann man das Board nach Belieben ein und abschalten.

  • Stop Mode: fast alle Clocks sind abgeschaltet (außer EXTI, da der Interrupt ja wieder einschalten soll). Flash, Ram und Peripherie sind aber immernoch eingeschaltet. Die Ausgangszustände werden beibehalten... eine eingeschaltete LED leuchtet also auch im Stop Mode weiter. (STM32 Verbrauch angeblich 14µA)
  • Standby: so ziemlich alles ist abgeschaltet. Der STM32 kann nun nur noch durch den Wkup Pin (A0) aktiviert werden. Wird der STM32 nach dem Standby wieder in Betrieb genommen, ist es generell wie ein Systemneustart bzw. Reset. Im Standby gehen auch alle GPIO Konfigurationen verloren. (STM32 Verbrauch angeblich 2µA)

Der Standby Mode ist als Befehl im Beispiel hinterlegt, aber Auskommentiert. Verwendet wird nur der Stop Mode, weil er den Energieverbrauch des Boards am weitesten nach unten fährt. Das mag angesichts der Beschreibung oben falsch erscheinen, hat aber seinen Grund:
Das LCD-Hintergrundlicht ist normalerweise mit einem Pullup Widerstand versehen. Wenn man diesen Pin also nicht belegt, ist das Display automatisch beleuchtet. Der Standby Mode schaltet aber alle Pins ab... sollte man die Hintergrundbeleuchtung also mit einem Low am BL-Pin abgeschaltet haben, geht sie dann wieder an, wenn der STM32 im Standby ist. Deshalb wird der Stop Mode benutzt, da er dafür sorgt, dass der BL-Pin auch seinen Zustand beibehält.

ADC
Es werden nur 2 Analogeingänge verwendet, weil die anderen Pins entsprechend belegt sind. Der eine (B0) ist an der Seite mit einem Trimmpoti verbunden. Der zweite (B1) ist über die Stiftleiste auffindbar. Beide Werte werden im HID-Report Versendet, sind ohne Änderung also nur vom PC aus zu sehen.

UART
Die UART Schnitstelle, auch gern Serieller Port genannt, kann mit einem Pegelwandler wie dem von mir hier verwendeten MAX3232CSE zur RS-232 gemacht werden. Auf dem Board ist ein USB-Seriell Wandler aber schon integriert und mit der UART1 verbunden. Man kann neben USB also auch den anderen Mini-USB Anschluss verwenden und den µC über die UART ansprechen. Bei meinem Beispiel wird die UART1 mit Baud 115200 betrieben und ist intern mit dem USB-HID Verbunden.

USB-HID
Das Board meldet sich als HID (Human Interface Device) an das System an. Unter Windows wird es als Eingabegerät im Gerätemanager angezeigt und macht erst mal nix weiter. Das Board ist so eingestellt, dass es weder Maus noch Tastatur beeinflusst. Es hat seine eingestellte PID und VID und wartet darauf, dass es angesprochen wird. Das DevTool ist darauf ausgelegt, ein solches HID-Device zu erkennen und anzusteuern. Am PC sind dann 64 Ein und 64 Ausgangsbytes verfügbar. Der Eingangsreport wird alle 64mS abgerufen (kann in _source\USB\usbdesc.c bei bInterval bis auf 1mS reduziert werden... auf Kosten der PC Auslastung). Wenn beide Mini-USBs an einem PC verwendet werden, dann kann man über USB-HID einen Text an das Board senden, welches über die UART den Text wieder an den PC zurück schickt. Oder man steckt die 2 Mini-USBs an 2 verschiedene Rechner und benutzt das Board als Datenbrücke. Dann kann man kleine Textnachrichten hin und her schicken... nicht wirklich sinnvoll, aber schön, dass es geht. Außerdem gibt es zum Testen einen Digitalen Eingang (Key1) und einen Digitalen Ausgang (LED2).
Weitere Infos hier: Dev Tools

Paint-Demo
Im Grunde ist es nur eine Mischung aus Touch und LCD Verwendung. Der µC liest die Stiftposition vom Touchscreen und setzt die entsprechenden Pixel auf dem LCD. Mehr ist es im Grunde nicht. Die ausgelesenen Stiftpositionen werden auch in den HID-Array übertragen, so dass bei verbundenem PC auf dem Monitor das schreiben mit verfolgt werden kann (aber nicht in der Performance, wie auf dem Board... das Ganze ist abhängig vom HID-Abfrage-Intervall). Im normalen Modus werden die Stiftpositionen links angezeigt und es werden große Pixel gezeichnet (4 Punkte auf einmal). Im schnellen Modus (wenn Key1 gedrückt gehalten wird) werden nur kleine Pixel (1 Punkt auf einmal) gezeichnet, die Stiftpositionen und die RTC Zähleranzeige werden hingegen nicht aktualisiert... das macht das ganze gekritzel dann relativ flott.

Button-GUI
Um eine einfache grafische Oberfläche zu erstellen, gibt es in lcd.c die Möglichkeit, Buttons zu erstellen. Dafür hab ich mehrere Arrays mit Einstellungen dort hinterlegt. Das ganze ist hinsichtlich Performance und Speicherausnutzung alles andere als ideal. Aber es ging mir auch erst mal nur darum, eine funktionsfähige Variante selbst hin zu bekommen.
Im Grunde ist es eine wiedermal einfache Sache. Eine Schaltfläche entsteht grafisch dadurch, dass man eine Box (ein ausgefülltes Rechteck) an die gewünschte Position zeichnet. Mittig auf der Box wird der Text darüber geschrieben. Dann werden noch zusätzliche Linien um die Box gemacht. Wenn die oben und links heller sind als die Box, sowie unten und rechts dunkler, dann erzeugt man den gewünschten 3D Effekt. Wenn diese 4 Linien ihre Farbe tauschen, dann hat man auch schon die "eingedrückte" Schaltfläche.
Gerade bei der GUI zeigt sich ein Grundproblem in der Entwicklung. Man muss sich zwischen Geschwindigkeit und Speichernutzung unterscheiden. Man kann (wie hier) ein paar Variablen deklarieren, in denen Größe, Position, Textinhalt und Status hinterlegt sind und die Grafischen Objekte dadurch erstellen lassen... was aber immer etwas zusätzliche Zeit mit diversen Berechnungen verbraucht. Außerdem werden die Pixel je nach dem in unterschiedlicher Reihenfolge (mal horizontal, mal vertikal) gezeichnet.
Man kann aber auch alle Schaltflächen als Bitmap im speicher platzieren. Dann wird einfach Pixel für Pixel vom Speicher auf den LCD übertragen, was sehr flott geht, aber eben auch Platz braucht. Wobei hier erwähnt werden muss, dass es sich um den Flashspeicher handelt, welcher bei den µC ja nicht umsonst höher ist als das RAM. Mit den verfügbaren Ressourcen wie die ST embedded GUI Lib beschäftige ich mich später mal.

#Board in Action

Board in Action

Die Schaltflächen haben einen leichten 3D Effekt. Wie vom PC bekannt, scheinen sie leicht nach vorn zu stehen und gehen nach innen, wenn man sie drückt. Außerdem wird dann die Farbe der Schrift grün, statt schwarz.
Wenn der Stift außerhalb des weißen Rahmens bewegt wird, werden die Punkte nicht auf dem Display dargestellt. So entsteht das Zeichenfenster.
Neben Weiss, können alle 3 additiven Grundfarben als Stiftfarbe benutzt werden. Alle verfügbaren Farben sind in dem Bild benutzt worden. Während mit dem grünen Stift gezeichnet wurde, hab ich die Key1 Taste gedrückt gehalten, wodurch der schnelle feine Modus aktiviert war.

#Version 004

Neben einigen eher kleineren Änderungen, sind folgende größere Punkte von Interesse gewesen:

I2C Bus (Vorgeschichte)
Der I2C ist ein 2 adriges Bussystem, welches auf Wikipedia und Mikrocontroller.net gut beschrieben wird. Daher belasse ich es diesen Seiten, die Grundinfos wiederzugeben und konzentriere mich auf das für mich zu nennende.
Mit dem I2C Bus des STM32 hatte ich viel zu kämpfen. Die Beispiele von ST hab ich mit dem I2C1 des Boards nicht zum Laufen bekommen. Das Programm blieb immer bei:
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
hängen. Aber auch mein Scanlogic-2 zeigte mir, dass sich da nix auf den 2 Leitungen tut.
Nachdem ich mich in einigen Foren umgeschaut habe und es nach einigen Versuchen immer noch bei einer konsequenten Nicht-Funktion blieb, hab ich mich entschlossen es anders anzugehen. Da ich noch eine I2C Softwareimplementierung hier hatte, wollte ich mich lieber darauf zu konzentrieren.
Das kleinere meiner 2 Kameraboards, benutzt zur Einstellung der Register den SCCB (serial camera control bus), welcher sich augenscheinlich kaum vom I2C Bus unterscheidet. Die Kommunikation lief softwareseitig über den µC. Es wurde ein Pin als Datenleitung und einer als Taktleitung deklariert. Dann wurde der Signalpegel der Pins entsprechend angepasst und der µC regelmäßig in die Warteschleife geschickt. Dadurch ergab sich letztendlich ein I2C artige Datenkommunikation zum Kamerachip.

I2C Bus (Umsetzung)
Die Software-I2C-Umsetzung (Bit-Banging) hat folgende Nachteile:

  • viel Code und damit auch etwas weniger Übersicht.
  • µC während der Datenkommunikation vollständig ausgelastet, er macht währenddessen nix anderes (lässt sich aber dadurch umgehen, dass man Timerinterrupts nimmt und über Variablen die nächsten Zustände schaltet. Dann kann der µC auch noch andere Sachen zwischendurch machen, aber das bedeutet noch sehr viel mehr und auch noch weiter verteilten und verschachtelten Code)
  • kein DMA

Aber eben auch folende Vorteile:

  • keine Pinfestlegung (ich benutze z.B. PinA8 als Clock und PinB1 als Datenleitung... alle anderen, waren auf dem Board belegt)
  • Freie Takteinteilung (der I2C hat ja verschiedene Geschwindigkeitsraten (100KHz, 400KHz, 3,4MHz), aber sofern der Chip mitmacht, kann man auch was dazwischen nehmen, mehr dazu weiter unten)

Den Code vom SCCB wäre auch ohne die Pullups ausgekommen (Push-Pull statt Open Drain Ausgänge), hätte aber kein Clockstretching (vom Slave gesteuerter Übertragungstimeout) unterstützt. Ich habs fast komplett überarbeitet und nun kann das Board, ohne auf USB, LCD, UART oder sonst was zu verzichten, mit I2C Geräten kommunizieren.

Der Hauptgrund für die Auseinandersetzung mit dem I2C, war die Verwendung des MCP23017 Chips. Dieser hat 16Pins, die als Eingang oder Ausgang deklariert werden können.
Er kann, wie bei meinem Picaxe Beispiel, mit dem I2C Fast Mode (400KHz) gesteuert werden, aber das Datenblatt verrät, dass er auch mit 1.7MHz gesteuert werden kann. Der Chip hat 3 Adresseingänge, mit denen können insgesamt 8 unterschiedliche Adressen eingestellt werden. Demzufolge können 8 Chips an einem Bus betrieben werden, sofern man keine Zwischenpositionen wie Umschalter benutzt.

Würde man so viele an einem Bus betreiben, dann hat man 128 Digitale Ein/Ausgänge, welche mit nur 2 µC Pins angesteuert werden können. Das dürfte Grund genug sein, sich mit beidem mal zu beschäftigen.

#16-Bit I/O Expander

Software I2C Test

Links im Bild kann man den Chip im DIL28 Gehäuse sehen. Der Port A wurde als Ausgang deklariert und ist entsprechend der Pin Nummern mit Port B verbunden... also A0 an B0, A1 an B1 usw. Dadurch kann man an Port A eine gewisse Belegung schicken und am Port B auslesen, ob sie auch eingestellt wurde. Diese Konfiguration habe ich verwendet, um über eine Schleife zu schauen, ob die Datenübertragung so klappt, wie sie soll. Die Verbindung A7->B7 ist nur gesteckt. Dadurch konnte ich sicherstellen, dass Bitfehler auch wirklich erfasst werden und nicht durch einen Auslesefehler unerkannt bleiben. Wenn die Leitung unterbrochen wird, steigt der Fehlerzähler impulsförmig an, da es ja schließlich nur das höchste Bit betrifft. Einen kurzen Zeitraum gibt es dann keine Fehler, dann ziemlich viele hintereinander, dann wieder kurz keine usw...

I2C mit Bitbang

In der aktuellen Einstellung läuft der I2C bei ca. 650 KHz. Höhere Raten sind mit entsprechenden Änderungen möglich... allerdings Soft- und Hardware. Hab ein paar Versuche mit größeren Geschwindigkeiten gemacht, aber es Funktionierte nicht. Später hab ich bei der Funktionierenden Variante mal mit dem Oszi ein Bild gemacht, wobei ich sehen konnte, dass die Übertragung schon recht grenzwertig abläuft.
Das Oszilloskopbild ist zwar nicht sonderlich groß, zeigt aber, dass da Kapazitäten ihren Einfluss haben. Da keine externen Kondensatoren mit den Leitungen verbunden sind, bliebe nur noch eine Verringerung der Pullup-Widerstände, wodurch der High-Pegel mit einem größeren Stromfluss herbeigeführt wird (dafür sind die Verluste und die Belastung für die Transistoren während der Kommunikation aber auch höher, da sie gegen die Pullups arbeiten).
Wenn man aber nur ein I2C Device ohne Clockstretching verwendet und von dem auch nicht lesen, sondern nur schreiben will, dann könnte man die Pullups auch weg lassen und die Pins als Push-Pull statt Open-Drain verwenden. Diese würden die Pegel dann entsprechend selbst erzeugen. Wobei man bestimmt auch lesen könnte, wenn man als Eingang mit Pull-Up statt Floating definiert. Wäre mal was zum probieren...

In der Programmschleife werden immer die Zahlen 0-255 übertragen. Sollte zwischendurch mal Ein- und Ausgabe nicht passen, wird es als Fehler gezählt. Der folgende Code zeigt die Funktion sinnbildlich:

//IO 16bit Expander Setup
#define IO16_DirA       0
#define IO16_OutA       18
#define IO16_OutB       19
I2C_Send(32,
 IO16_DirA,
 0); //Direction Port A: alle Pins Out

//Datenaustausch in der Schleife
I2C_Send(32,
 IO16_OutA,
 b_send); //adr,
 reg,
 data
I2C_Read(32,
 IO16_OutB,
 &b_recive); //adr,
 reg,
 *data

if (b_send!=b_recive) { errorcount++; }

Die LED wurde zu Beginn eingeschaltet. Sie wird abgeschaltet, wenn die Datenleitung als Eingang definiert wird. Wenn sie danach wieder zum Ausgang umgestellt wird, ist auch die LED wieder aktiv. Zwischen dem Datenaustausch ist sie darum auch ab und zu aus. So kann man am Verlauf der LED sehen, ob die Datenleitung Ein oder Ausgang war, was zur Interpretation dessen, was man da auf dem Logicanalyzer so sieht, schon recht hilfreich war.

ADC – DMA
Da B1 jetzt für den I2C verwendet wird, ist jetzt nur noch der B0 (Trimmer) als Analogeingang vorhanden. Nur wird jetzt der ADC nicht sequenziell einzeln ausgelesen, sondern zyklisch automatisch. Die Messwerte werden per DMA (Direct Memory Access) direkt in eine 16Bit Variable gespeichert. Dadurch ist das Ganze auch wesentlich schneller. Die Variable wird einfach dargestellt, anstatt erst mal ein ADC Scan zu machen.

LCD Codeeffizienz
Die meisten der LCD Funktionen sind inzwischen von mir überarbeitet worden. Die alten haben zwar auch gut funktioniert, aber die neuen arbeiten effizienter. Ein LCD im 8Bit-Latch-Mode ist jetzt sehr viel schneller als ein 16Bit mit dem alten Code.
Hier mal als Beispiel die Funktion zum zeichnen von horizontalen oder vertikalen Linien:

//alter Code
void LCD_WriteRAM(u16 rgb_Code) {
    LCD_WriteData(rgb_Code);
    LCD_WR_L();
    LCD_WR_H();
}
void LCD_DrawLine(u16 xpos,
 u16 ypos,
 u16 length,
 u8 direction,
 u16 color) {
    u32 i = 0;

    LCD_SetCursor(xpos,
 ypos);

    if (direction == LCD_LINE_VERTICAL) {
        for (i = 0; i < length; i++) {
            LCD_WriteRAM(color);
        }
    } else {
        for (i = 0; i < length; i++) {
            LCD_WriteRAM(color);
            xpos++;
            LCD_SetCursor(xpos,
 ypos);
        }
    }
    LCD_CS_H();
}

//neuer Code
void LCD_DrawLine(u16 xpos,
 u16 ypos,
 u16 length,
 u8 direction,
 u16 color) {
    u16 i = 0;

    LCD_SetCursor(xpos,
 ypos);
    if (direction == LCD_LINE_VERTICAL) {
        LCD_WriteRegister(0x0003,0x1030);       //Entry Mode vertical
        LCD_WriteRAM_Prepare(); LCD_WriteData(color);
        for (i = 0; i < length; i++) {
            LCD_WR_L(); LCD_WR_H();
        }
    } else {
        LCD_WriteRegister(0x0003,0x1018);       //Entry Mode horizontal
        LCD_WriteRAM_Prepare(); LCD_WriteData(color);
        for (i = 0; i < length; i++) {
            LCD_WR_L(); LCD_WR_H();
        }
    }
    LCD_CS_H();
}

Die Wirkung wird besonders deutlich, wenn man sich vor Augen hält, was der µC da eigentlich macht.

Zuerst wird der Startpunkt in 2 Register übertragen, das ist bei beiden gleich.
Von da aus wurde für die vertikale Linie die Farbe auf den Datenbus geschrieben und mit einem Takt übertragen.
Wenn die Linie aber sowieso die gleiche Farbe hat, dann braucht man die Farbe nur einmal auf den Datenbus schicken und danach nur noch durchtakten. Bei der horizontalen Linie war man noch verschwenderischer... es wurde ein Pixel mit einer Farbe übertragen, dann der Cursor neu gesetzt und der nächste Pixel übertragen.
Im neuen Code wird nachdem die Cursorpositionen übertragen wurden, in einem Steuerungsregister festgelegt, in welche Richtung die Pixel gezeichnet werden, wenn es einen Takt gibt. Dann wird das Ram-Register angewählt und die Farbe übertragen. Zum Schluss wird pro Pixel nur noch einmal durchgetaktet. Beide Linienarten werden gleichschnell dargestellt. Wenn eine Linie von 5 Pixeln auf 10 verlängert wird, verdoppelt sich dadurch nicht die Arbeit (und Ausführungszeit) des µC. Je länger die Linien werden, desto mehr fällt sowas ins Gewicht.
Hier noch ein Beispiel, mit einem gefüllten Rechteck:

//alter Code
void LCD_DrawBox(u16 xpos,
 u16 ypos,
 u16 height,
 u16 width,
 u16 color) {
//Displays a box (filled rectangle).
    u32 curY;

    for (curY = xpos; curY < (ypos + height); curY++) {
        LCD_DrawLine(xpos,
 cury,
 width,
 LCD_LINE_HORIZONTAL,color);
    }
}

//neuer Code
void LCD_DrawBox(u16 xpos,
 u16 ypos,
 u16 height,
 u16 width,
 u16 color) {
//Displays a box (filled rectangle).
    u32 curY=0; u16 i = 0;
    LCD_WriteRegister(0x0003,0x1018);       //Entry Mode horizontal
    LCD_SetWindows(ypos,320-(xpos+width),ypos+height-1,319-(xpos));
    LCD_SetCursor(xpos,ypos);
    LCD_WriteRAM_Prepare(); LCD_WriteData(color);
    curY=height*width;
    while(curY--) {
        LCD_WR_L(); LCD_WR_H();
    }
    LCD_SetWindows(0,0,239,319);
}

Bei der Box wurden einfach immer neue horizontale Linien erzeugt. Ungünstiger weise genau die besonders ineffiziente Linienart oben.
Jetzt wird direkt im Register festgelegt, von wo bis wo die Box dargestellt werden soll. Dann wird der Cursor in die Anfangsecke gesetzt, die Farbe übertragen und einfach nur noch durchgetaktet. Bei einer sehr kleinen Box ist der alte Code schneller, aber ab einer gewissen Größe, die selbst die Schaltflächen für die Stiftfarben locker übersteigen, ist der neue Code schneller und effizienter. Die Boxfunktion wird verwendet, um das gezeichnete wieder zu löschen. Dafür wird eine schwarze Box innerhalb des weißen Rahmens gezeichnet. Da sieht man die Unterschiede in der Geschwindigkeit auch recht gut.

Stiftposition auslesen
Jetzt wird das Touchpanel nicht so schnell hintereinander ausgelesen, was ein geringeres Rauschen zur Folge hat. Außerdem wird bei einer Positionsabfrage 4x für X und 4x für Y ausgelesen und anschließend durch 4 geteilt. Durch die geringere Datenrate und das 4fach Mitteln der Messwerte, ist das Auslesen zwar langsamer, aber auch genauer.
In Verbindung mit den LCD Verbessrungen, zeichnet man mit der neuen Board-Firmware trotzdem schneller und nun auch genauer als vorher. Außerdem ist der HID-Abfrageintervall reduziert worden, wodurch man auf dem PC das geschriebene jetzt besser verfolgen kann.

Font 8x16
Bisher wurden nur alle Ascii Zeichen dargestellt. Jetzt ist die lcd_font.h entsprechend erweitert worden, wodurch Charcodes 32 bis 255 (Leerzeichen bis ÿ) dargestellt werden können. So ist einerseits etwas Platz für eigene Kreationen, aber auch Umlaute werden jetzt mit dargestellt.
Jetzt heißt es auch nicht mehr Gruen sonder Grün. Das Dev-Tool wurde mit der Version 18 außerdem um einen rudimentären Font-Editor erweitert.

GUI Mode
Dieser Modus kann nur vom DevTool_018 aus aktiviert werden. Damit kann man 2 Texte oder 2 Buttons (ID:0 und 1) über den PC einstellen.
Bisher hab ich für die Schaltflächen und Texte immer ein paar Variablen angepasst und mir nach übertragen und starten die Wirkung angesehen. Das dauert natürlich immer etwas, bis die Darstellung den eigenen Wünschen entspricht.
Daher hab ich den GUI Modus entwickelt, welcher mit nur 2x Text und 2x Button zwar nicht viel kann, aber doch einiges an Zeit spart.
Man stellt am PC die Parameter ein (Schriftfarbe, Position, Text...) und über HID wird das direkt auf dem Board eingestellt. Die Nummern (Positionen, Größen...) werden über NumericUpDown-Steuerelemente eingestellt. Die kann man mit Mausrad, Tastaturpfeilen oder Direkteingabe der Werte, recht entspannt bedienen. Das Resultat sieht man direkt auf dem Boarddisplay. Ist man mit dem was man sieht zufrieden, kann man den entsprechenden Code einfach raus kopieren und in seinen µC-Quellcode einfügen. Der Code wird bei der Änderung der Parameter erzeugt (genau wie die HID Befehle, die gleich an das Board gehen).
Die Buttons sind inzwischen übrigens nicht mehr als mehrere Einzelarrays, sondern als Objektstruktur gespeichert. Das ist etwas übersichtlicher und um einiges platzfreundlicher.

Testzeichung mit V004

Paint Mode:
Hier die neue Variante mit umlauten. Auch der Rahmen der Schaltflächen wurde von 1Pixel auf 2 erweitert, was mir von der Darstellung besser gefällt.
Das Zeichnen geht hier um einiges schneller.


Gui Mode: Board

GUI Mode:
Hier ein Beispiel mit beiden Texten und 2 Buttons. Texte werden einfach reingeschrieben. Buttons sind Objekte, die bestehende überschreiben. Deshalb verschwinden in diesem Beispiel die Schaltflächen für Weiss und Rot, sobald man den Bildschirm löscht. Hier sind sie nur noch zu sehen, weil beim überschreiben ihre alte Position nicht extra gelöscht wird.


Gui Mode: DevTools 18

DevTools 18 (GUI Mode):
Hier die Einstellungen im DevTool. Bei dem Text kann man Vorder- und Hintergrundfarbe über Farbwähler einstellen. Die sind allerdings je nach Bildschirmeinstellung auf dem PC auch gerne mal mit 32Bit Farben. Deshalb kann man weit mehr Farben auswählen, als am Ende dargestellt werden. Aber man sieht ja auf dem Display, wie die Farbe wirkt.

#Version 005

GUI der Version 005

Die Änderungen betreffen vorwiegend die lcd.c Datei.
Zum einen sind nun die Bytes 0-31 darstellbar, welche vorher als Steuerzeichen nicht erfasst wurden. Jetzt sind sie durch kleine Symbole ersetzt (und damit kann nun von 0-255 jedes Zeichen laut lcd_font.h dargestellt werden).
Außerdem gibt es ein neues Grafikobjekt... die Progressbar. Dieser Balken kann Vertikal (aufsteigend) oder Horizontal (nach rechts laufend) erstellt werden. Die Farbe ist wählbar und das Maximum darf bis zu 65535 Betragen (Min ist immer 0). Die Progrssbar ist in diesem Beispiel mit Key2 verknüpft.

Während vorher das Board durch die Taste direkt in den Stop-Mode versetzt wurde, wird jetzt die Zeit gezählt, die Key2 gedrückt gehalten wurde. Diese Zeit wird dann auch als Balken dargestellt. Wird die Taste lang genug gedrückt, geht das Board in den Stop-Mode.

Außerdem gibt es neue Darstellungsfunktionen, wie z.B. LCD_DrawLine2 und LCD_DrawEllipse. Beide benutzen den Bresenham-Algorithmus und sind in ihrer Berechnung komplexer, aber eben auch vielseitiger.
LCD_DrawLine kann nur Horizontale und Vertikale Linien, diese dafür aber sehr schnell. LCD_DrawLine2 kann von irgendeinem Startpunkt bis irgendeinem Zielpunkt die Linie Zeichnen.

Außerdem wurden Funktionen eingefügt, damit der GUI-Mode des Dev-Tools_019 mit diesem Board funktioniert.

#Version 006

Bei dieser Version wurde die Ordnerstruktur verändert, um mehr Übersichtlichkeit und Modularisierung zu erhalten. Jetzt sind Beispielsweise alle benötigten Dateien für das Display im Ordner _LCD, alle für USB in _USB usw.

GUI der Version 006

LCD Erweiterung
Ich bin auf die LCD Schriftarten Sammlung gestoßen und hab mich ordentlich bedient. Somit sind nun 8 Schriftgrößen verfügbar.

Außerdem sind neben Texten in unterschiedlichen Schriftgrößen nun auch Schaltflächen in unterschiedlichen Schriftgrößen und Farben möglich.
Bei Schaltflächen kann nun eine Vordergrundfarbe (Schriftfarbe) und Hintergrundfarbe (Schaltflächenhintergrund) definiert werden. Durch das drücken der Schaltfläche wird beides invertiert dargestellt.
Die Schaltfläche mit Anzeige wurde in Switch umbenannt und wechselt nach jedem klick zwischen Vorder und Hintergrundfarbe. Der Zustand kann auch im Code über eine Statusnummer abgefragt werden. Mit if (LCD_GetButtonstate(5)==BtnIsOn) ... kann z.B. abgefragt werden, ob die Schaltfläche Nr. 5 eingeschaltet wurde.
Durch diese Änderungen funktioniert der GUI Editor nur vom DevTool_V020 richtig.

Versionsupgrade
Ursprünglich wollte ich die neue ST Standard Peripherie Library V3.6.1 und die USB Lib 4.0.0 verwenden, aber das hab ich nach einigen Anläufen einfach nicht hin bekommen. Das Board ist entweder beim initialisieren von USB stecken geblieben, oder wurde nicht als Gerät erkannt.
Ich hab die Vorlage von ST so angepasst, das auf meinem MiniSTM32Board zumindest die Costum-HID-Demo lief.
Aber eine Blinkende LED blinkte nur, solange der USB verbunden ist und außerdem war das Blinken deutlich langsamer als erwartet (ohne USB war es schnell genug, es war also keine zu geringe Takteinstellung). Ich hab ein paar mal hin und her probiert und es dann gelassen.

Letztendlich wollte ich die neue Version nicht, weil ich eine Funktion vermisst hab, sondern nur, um dann ein funktionstüchtiges Projekt mit der neuen Version zu haben...also nur um sagen zu können "es ist auf dem neusten Stand". Vielleicht werde ich es später nochmal versuchen, aber fürs erste erfüllt die gegenwärtige konfiguration wie gewollt ihre Funktion.
Aktuell benutze ich also eine modifizierte ST StdPerLib 2.0.1 und die USB Lib 1.1, aber die Fat FS ist auf 0.10 erweitert worden.

Normal und Fast (mit Stift schnell)

Fast Paint
Die Funktion macht wonach sie benannt wurde und funktioniert eigentlich recht einfach.
Wenn die Funktion mit einem Klick auf den Switch "Fast" aktiviert ist, werden die Anzeigen (X, Y, Time und Analogwert) nicht mehr aktualisiert, solange sich der Stift im Zeichenbereich befindet.

Da die "font_8x16" verwendet wurde, hat man 8 x 16 also 128 LCD Schreibvorgänge und das pro Zeichen. Außerdem werden für eine Variable wie X mehr Zeichen gebraucht, als man sieht. Ein "X: up" mag nur aus 5 Zeichen bestehen, es sind insgesamt aber 7, da die nicht sichtbaren Leerzeichen den ganzen Bereich überschreiben. Wäre es nicht so, würde folgendes passieren:

  • Hätte man z.B. einen Wert von 1000, würde auf dem LCD "X: 1000" stehen.
  • wäre der nächste Wert 28, würde auf dem LCD "X: 2800" stehen, da die letzten beiden ja nicht überschrieben werden.

Zuständig für die korrekte Darstellung ist die Funktion LCD_DrawTextBlock. Sie benötigt zusätzlich ein Füllzeichen und die Menge der Gesamtzeichen.

Fat SD Filesystem
In der oben schon erwähnten Vorlage (Mini-STM32 Digital Picture Frame von hier) wurden Bilder aus einem Ordner der SD Speicherkarte auf dem Display dargestellt. Wer sich für diese Funktion interessiert, sollte sich die Vorlage besorgen, ich hab mich nur mit dem Zugriff auf die SD Karte genauer beschäftigt. Es war schon ein ziemlicher Akt, diesem Board USB und den Fat SD Kartenzugriff bei zu bringen. Entweder wurde nicht mit der SD richtig Kommuniziert, oder der USB funktionierte nicht.

Aber nun funktioniert beides, was in Kombination einige nette Möglichkeiten bringt.
Man könnte z.B. Dateien von der SD Karte über HID auf den PC Streamen. Sie ließen sich zwar nicht ausführen, es wäre also kein HID Laufwerk, aber hoch und runterladen wäre möglich.

Testweise sind 4 Funktionsblöcke eingebaut:

  • Read Disk
    Alle Dateien und Ordner werden aufgelistet. Wenn ein Ordner gefunden wurde, wird er geöffnet und dort drin nach Dateien gesucht.
  • Read TXT
    Eine Datei wird Zeilenweise ausgelesen und angezeigt. Es muss nicht .txt sein, sie kann auch .dat oder anders heißen.
  • Write TXT
    Der Text "neue Testzeile\r\n" wird an die Datei angefügt. Man kann auch Überschreiben... dann wird (sofern der Filepointer nicht anders gesetzt wird) am Anfang der Datei so viel Überschrieben werden, wie man Daten in die Datei rein schiebt. Wenn die Datei nicht existiert, wird sie erstellt.
  • Del TXT
    Die angegebene Datei wird gelöscht. Der SD-Karteninhalt wird dann wieder automatisch angezeigt, da nach dem Löschen automatisch die Funktion von Read Disk aufgerufen wird.

#Datein auslesen und erweitern

Datei auslesen und erweitern

Oben links:
Eine Testweise erstellte Textdatei wird geöffnet und ausgelesen.
Oben rechts:
Eine Zeile wird hinzugefügt. Es wird angezeigt was geschrieben wurde, ob der Writevorgang ausgeführt wurde, wie viel Zeichen geschrieben wurden und wie groß die Datei nun ist.
Unten links:
erneutes Auslesen der Textdatei.
Unten rechts:
alle Dateien und Ordner werden angezeigt.

#Datei löschen und neu erstellen

Datei löschen und neu erstellen

Oben links:
Die Textdatei wurde gelöscht, was auch die folgende Dateianzeige zeigt.
Oben rechts:
Die Funktion wurde nochmal ausgeführt. Da die angegebene Datei aber schon gelöscht ist, wird sie nicht zum Löschen gefunden, weshalb die Funktion auch "INVALID_NAME" rückmeldet.
Unten links:
Nachdem 4x auf Write TXT gedrückt wurde, ist die Datei nun mit 4 gleichen Zeilen wieder vorhanden.
Unten rechts:
Inhalt der Textdatei anzeigen.

Unten rechts auf dem Display ist die Schaltfläche UART zu sehen. Wenn die Funktion eingeschaltet ist (Standardzustand) dann wird jede Textzeile, die auf dem LCD dargestellt wird, auch automatisch auf Uart1 ausgegeben. Dieser ist mit einem onboard USB-Seriell Wandler über den rechten Mini-USB Port leicht erreichbar.

Als SD Karten hab ich 2GB und eine 4GB (SDHC) getestet. Mit Dateisystem Fat32 klappte es. Eine 2GB Karte wird in Windows als FAT angezeigt, aber vom Board nicht erkannt. Das kann aber auch daran liegen, das die Kontakte nicht mehr die besten sind, nachdem sie mal angelötet waren.
So bald bei V006 auf FatSD geschaltet wird, wird zuerst das Filesystem gemounted. Wenn dann in grün "Init PASS" steht, ist das schon mal ein gutes Zeichen. Fehlende oder falsch Formatierte Karten werden jedenfalls mit einem roten "Init FAIL" angezeigt und dann ist davon auszugehen, dass die 4 Testfunktion auch nicht arbeiten.

Die Hardwaretasten sind auch anders belegt. Beim drücken auf Key1 läuft der Balken im Paint Beispiel (bei Fat SD hat die Taste keine Funktion), ist der Anzeigebalken durchgelaufen, ändert er seine Farbe von blau zu rot und die LED2 beginnt so lange zu blinken, bis Key1 losgelassen wird... dann wird das Board direkt in den StopMode versetzt.
Wenn man Key1 dann nochmal drückt wird, Blinkt die LED2 wieder so lange, bis die Taste losgelassen wird.
Die Taste Key2 schaltet zwischen Paint und Fat SD um.

#Version 007

Inzwischen ist es mir gelungen, die USB Lib 4.0.0 und die StdLib 3.6.1 in einen funktionstüchtigen Zustand zu bekommen. Die alte Version ließ sich nicht auf CodeBlocks EPS portieren, weshalb ich mich nochmal genauer mit der neuen Version auseinandergesetzt hab.
Ich konnte CodeBlocks nicht dazu bringen ein "__packed" vor Strukturen zu akzeptieren (darum ging die alte Version nicht), um den unaligned accesses zu nutzen. Damit werden Variablen im Speicher nebeneinander gepackt so entstehen keine ungenutzten Lücken:
ARM Compiler toolchain Compiler Reference.
Die USB lib hat nun sehr viel mehr Dateien eingebunden, ist im fertigen Code aber kleiner.
Bei usb_istr.c musste "Suspend();" auskommentiert werden, ansonsten wurde nicht mal das LCD initialisiert.
Nachdem die Funktion auskommentiert wurde, konnte Stück für Stück alles auf beiden IDEs zu laufen gebracht werden.
Inzwischen hab ich auch meine Graphfunktion fertig, welche nun mit dabei ist.

16Bit Mode
Für meine Basteleien benutzte ich bevorzugt den 8bit Latch Mode, da ich so mehr benutzbare Pins am µC habe und auch weniger Aufwand bei der Verdrahtung. Aber das Board ist auf den 16Bit Modus ausgelegt und die freien Pins sind wegen der Steckerleiste auch nicht nutzbar.
Außerdem sehe ich an den Downloads, das der 16Bit Modus mehr als doppelt so oft angefragt wurde, daher hab ich mich dazu entschlossen, bei dem Board nur noch den 16Bit Modus zu verwenden.
Inzwischen ist die Struktur auch so weit geändert, dass man nur noch bei boardcfg.h was auskommentieren muss, um den entsprechenden Modus zu haben, die GPIOs werden automatisch konfiguriert. Im 16Bit Modus braucht man nämlich alle Datenleitungen als Ausgänge, da sie ja das Signal transportieren sollen. Aber im 8Bit Latch Mode, müssen die Pins für D0 bis D7 als Eingänge konfiguriert werden, weil sie sonst mit den Latchausgängen kollidieren.
(Die Brücke auf der Displayrückseite, wo "8Bit Mode" steht, bedeutet eigentlich nur, dass die Ausgänge des Latches eingeschaltet werden)
Ab jetzt kann man mit Use_LCD_8Bit_Latch oder Use_LCD_8Bit_Direct den 8Bit Modus wählen, sind beide auskommentiert (Standard), gilt der 16Bit Modus.

#USB Verbindung

Bei der neuen USB lib darf kurz nach der USB Verbindung der µC nicht zu stark beschäftigt sein, sonst meldet sich das Board nicht richtig an und der PC meldet "USB-Gerät wurde nicht erkannt". Deswegen wird nach der Erkennung einer neuen USB Verbindung das Board in eine Warteschleife geschickt, bis die Konfiguration abgeschlossen ist.

USB Verbindung

Oben links:
Normalzustand.
Oben rechts:
Stecker eingesteckt, Board befindet sich in der Anmeldungsschleife. Die dauert so lange, bis die Verbindung hergestellt wurde. Wenn es länger als 3 Sec dauert, kann man den Stecker auch nochmal abziehen und neu verbinden. Üblich sind 0.5 bis 2 Sec Anmeldezeit.
Unten links:
Anmeldung erfolgreich. Dies ist nur eine Anzeige, welche nach 0.5 Sec von selbst verschwindet... danach sieht man wieder den Normalzustand... also Graph, Paint oder Fat SD... je nachdem, was gerade aktiv war.
Unten rechts:
Usb Trennung erkannt. Dies ist nur eine Anzeige, welche nach 0.5 Sec von selbst verschwindet.
Erkannt wird es durch eine Time-out Variable. Die wird jedes Mal beim abrufen des HID-Reports neu gesetzt und durch den Systick-Timer wieder runter gezählt. Wenn die Variable weit genug runter gezählt wurde, gab es in der Zeit keine HID-Reportabfragen... also entweder eine getrennte oder fehlerhafte USB-Verbindung.

CodeBlocks EPS
Die IDE hab ich beim STM32F4 Discovery Paintboard schon verwendet und wollte sie auch hier benutzen. Leider ist es mir nicht gelungen, den Debugger zum Laufen zu bekommen. Daher bleibt für das erste nur die Möglichkeit, den Code im Releasemodus auf dem Board ausgiebig zu testen. Die Projektdatei ist wieder darauf eingestellt, bei einem erfolgreichen Build, direkt auf das Board zu Flashen. Was mir beim F4 Discovery aber noch nicht aufgefallen ist:
unbenutzter Code wurde mit eingebunden, was die letztendliche Dateigröße unnötig in die Höhe treibt... und in meinem Fall sogar die Flashgröße überstiegen hat.
Ohne Optimierung war die Flashgröße bei 138k, was interessanterweise aber noch Funktioniert hat (der µC hat nur 128k).
Mit nachträglicher entfernung unbenutzter Funktionen und Variablen, ist die Flashgröße nur noch bei 122k.
Außerdem gibt es 2 eingestellte Releaseversionen:
Release_Speed: Braucht mehr Platz im Flash, ist aber schneller in der Ausführung.
Release_Size: etwas langsamer aber auch kleiner als _Speed.

ADC, DMA und Encoder
Verwendet werden Ain8 und Ain9 (B0 und B1) weshalb auch der Software I2C deaktiviert wurde (Code ist noch da, aber eben nicht in Verwendung).
Der ADC ist darauf eingestellt, erst Ain8 und dann Ain9 aufzunehmen, dann wieder Ain8 usw. Der DMA ist darauf eingestellt, nach jeder ADC-Datenerfassung die Messwerte in einem Array abzulegen.
Dadurch ist im Hauptprogramm nur noch der Array "AdcValues", wobei in AdcValues[0] der letzte Wert für Ain8 und bei AdcValues[1] der letzte Wert für Ain9 liegt. Den Code auf weitere zu erweitern, sollte bei der gegenwärtigen Struktur kein Problem sein, sofern man denn wollte.
Die Buttons Key1 und Key2 sind zurzeit nicht in Betrieb, da jetzt ein Encoder verwendet wurde. Dafür ist der Timer2 im Encodermode Konfiguriert: Ch1 auf A0 und Ch2 auf A1
Zum Glück sind die Buttons mit Pullups ausgeführt (aktiv Low), wären es Pulldowns würde es so nicht gehen, da der Encoder gegen GND schaltet.

#Graph Funktion

SWD Debugger und Graph

Oben links:
Der neue Debugger ist beim STM32F4 Discovery Paintboard schon auf dem Board. Ich hab nur den F4 µC und die SWD Verbindung dahin unterbrochen. So kann das Miniboard per SWD geflasht werden. Codeblocks unterstützt leider den ST-Link V1 nicht, daher hab ich ein F4 Discovery geopfert.
Oben rechts:
Graphfunktion im Einsatz mit einem NF-Signalgenerator. Da der ADC nur positive Spannungen bis 3.3V verträgt (VCC) hab ich einen Pulldown Widerstand und eine einfach Diode verwendet, um wenigstens die positiven Halbwellen zum Testen zu haben.
Unten links:
Getriggertes Testsignal mit 64Hz.
Unten rechts:
Getriggertes Testsignal mit 7.5kHz... es ist zu schnell zum erfassen. Da die Messungen aber in etwa in der Geschwindigkeit abläuft, dass sie beim nächsten Messpunkt eine der folgenden Kurven erwischt entsteht der Eindruck einer unsauberen Kurve. In Wirklichkeit ist jeder Messpunkt von einer anderen Kurve. Mit dem richtigen Timing, würde die Kurve sauber aussehen, außerdem wären dann auch die abgeschnittenen Halbwellen zu sehen.

Graph
Die Graphfunktion ist dazu da auf 2 verschiedene Arten Kurven darzustellen. Beide Funktionen können ein einstellbares Hintergrundgitter haben und werden Spaltenweise dargestellt.
Mit Spaltenweise ist gemeint, dass in jeder Spalte zuerst mit dem Hintergrund überschrieben wird (um ältere Darstellungen zu überschreiben) und dann der entsprechende Wert darüber geschrieben wird. Dafür gibt es 2 Darstellungsbeispiele:
Roll: stellt den neusten Wert ganz rechts dar und nach links wird entweder mit älteren Messwerten oder bis zur Darstellungsgröße aufgefüllt.
Da die Funktion nach jedem Mal aufgerufen wird, wenn zur Kurve ein neuer Wert hinzugefügt wurde, entsteht der Eindruck einer von rechts nach links laufenden Kurve... so als würde man auf einen EKG Schreiber schauen. Im Beispiel wird ein Delay verwendet, man kann aber genauso gut einen RTC Interrupt verwenden und erhält somit einen Zeitlich genauen Verlauf.
Frame: stellt den ältesten Wert ganz links dar. Nach rechts wird mit späteren Messwerten oder bis zur Darstellungsgröße aufgefüllt.
Zuerst wird in einer Schleife ein Buffer mit Messwerten gefüllt, die dann in die Kurven kopiert und dargestellt werden. Die Anzeige wird zwar nicht so oft aktualisiert wie im Roll Mode, aber die Kurve stellt eine sehr viel schnellere Messwertänderung dar. Die Delays sind so eingestellt, dass sie eine 50Hz Schwingung darstellen, wenn man ungeerdet den Pin berührt (und selbst als Antenne funktioniert).

#Graphfunktion

Graphfunktion

Oben links:
Roll Modus mit kurzzeitigen berühren des B1 Analogeingangs. Der andere ist auf dem Board mit dem Trimmpoti verbunden.
Oben rechts:
Während des Durchlaufens wurde die Hintergrundfarbe von Kurve B1 auf gelb geändert. Diese Funktion kann auch dazu benutzt werden, um die Kurve selbst als Signal zu werten. Beispiel: Wert zu hoch -> Kurve wird rot.
Unten links:
Die 50Hz Schwingung im Frame Modus. Außerdem ist der Trigger eingeschaltet. Der Trigger macht nix weiter, als erst die Kurve aufzunehmen, wenn der Triggerwert erreicht wurde. Dadurch hat man im Idealfall eine sauber stehende Kurve. Die Erfassung ist aber noch nicht besonders Präzise... aber es läuft schon mal.
Unten rechts:
Hintergrundfarbe, Mittellinienfarbe und Gitterfarbe sind ebenfalls einstellbar, wodurch man hier mal eine andere Darstellungsart sehen kann.

#Download

stm32 64pin v006 usblcd16paintfat (ZIP, 2.82 MB)

Enthält die Projektdatei, den Quellcode (vorwiegend C), ein paar Datenblätter und eine Pinbelegungs Excel.
Mit 16Bit LCD Verbindung (Lieferzustand des Boards).
Ansonsten ist alles gleich mit der 8Bit Latch Version (info an mich, falls die einer haben will).

ministm32 v007 usblcdpaintfatgraph (ZIP, 3.33 MB)

Enthält die Projektdateien (Keil und CodeBlocks), den Quellcode (vorwiegend C), ein paar Datenblätter, GUI-Konfigurationen und eine Pinbelegungs Excel.


Zuletzt geändert am: Mär 05 2014 um 8:04 PM

© by joe-c, 2023 - 2024. All Rights Reserved. Built with Typemill.