Über den Beitrag
In diesem Beitrag gehe ich auf den Mikrocontroller LGT8F328P ein und zeige, wie ihr auf ihm basierende Entwicklungsboards der Version LQFP32 in der Arduino Umgebung programmiert. Da der LGT8F328P dem ATmega328P nicht nur namentlich nahesteht, werde ich vor allem die Unterschiede erläutern.
Folgendes kommt auf euch zu:
- Überblick
- Vorteile gegenüber dem ATmega328P
- Pinout der LGT8F328P-LQFP32 basierten Boards
- Installation der Board Pakete
- LGT8F328P-LQFP32 Boards in Action
- Den LGT8F328P basierten Pro Mini programmieren
- Fazit
Überblick
Der LGT8F328P wird von dem chinesischen Unternehmen LogicGreen (mittlerweile anscheinend: Prodesign Semiconductor) hergestellt. Er ist mit dem AVR-Befehlssatz und dem ATmega328P weitestgehend kompatibel. Dabei ist der LGT8F328P günstiger und weist gegenüber dem ATmega328P einige technische Vorteile und zusätzliche Funktionen auf. Deshalb verwundert es nicht, dass er dafür verwendet wurde, Pendants zum Arduino UNO R3, Arduino Nano 3 und Arduino Pro Mini zu entwickeln. Und genau diese Boards behandle ich in diesem Beitrag.
Am weitesten verbreitet sind die Nano und Pro Mini kompatiblen Boards, die ihr unter der Bezeichnung „LGT8F328P LQFP32 MiniEVB“ in Online-Shops für wenige Euro bekommt. Das von mir getestete Arduino UNO kompatible Board stammt von AZ-Delivery. Es ist in einigen Aspekten etwas anders als die anderen Boards.
Den LGT8F238P IC gibt es als SSOP Ausführung mit 20 Pins (SSOP20), als QFP mit 48 Pins (QFP48L) oder als QFP mit 32 Pins (QFP32L). In diesem Beitrag behandele ich nur QFP32L basierten Boards, die den ATmega328P basierten Vertretern am nächsten stehen. Meistens sind sie mit dem Aufdruck „LQFP32“ versehen. In einem Folgebeitrag werde ich noch einmal auf alle drei Ausführungen eingehen. Sie besitzen dieselben Register und unterscheiden sich im Wesentlichen nur darin, welche Funktionen durch Pins tatsächlich zugänglich sind.
Das Pinout Schema des QFP32L zeigt viele Übereinstimmungen mit dem des ATmega328, aber auch ein paar zusätzliche Funktionen.
Ein gewisser Nachteil beim Arbeiten mit dem LGT8F328P ist, dass der Hersteller kein englisches Datenblatt zur Verfügung stellt. Dank einiger fleißiger Mitmenschen gibt es aber Übersetzungen, beispielsweise hier auf GitHub.
Vorteile gegenüber dem ATmega328P
Ich möchte hier nicht alle technischen Eigenschaften des LGT8F328P „herunterbeten“. Wie der ATmega328P hat er 2 KB SRAM, 32 KB Flash, die Versorgungsspannung liegt zwischen 1.8 und 5.5 Volt usw.
Deswegen hier eine Auswahl wichtiger Unterschiede zum ATmega328P (ohne Anspruch auf Vollständigkeit):
Pinout der LGT8F328P-LQFP32 basierten Boards
Vergleicht man die LGT8F328P Boards mit ihren ATmega328P Pendants, muss man schon zweimal hinschauen, um Unterschiede zu erkennen. Das gilt insbesondere für die Pinbezeichnungen. Hier seht ihr einen originalen Arduino Nano (blau), umrahmt von zwei LGT8F328P Nano Boards:
Auch hinsichtlich der Pinfunktionen gibt es große Übereinstimmungen mit den Originalen:
Ein entsprechendes Schema für den LGT8F328P basierten Pro Mini findet ihr beispielsweise hier. Für das von mir getestete Board im Arduino UNO Stil (Bezugsquelle: AZ-Delivery) habe ich kein solches Schema gefunden. Das sollte aber kein Problem sein, da der UNO die gleichen Ausgänge hat. Lediglich SWC und SWD sind nicht ausgeführt.
Installation der Board Pakete
Nano / Pro Mini Style
Um die LGT8F328P Boards mit der Arduino IDE programmieren zu können, müsst ihr zunächst ein geeignetes Board Paket installieren. Für den „L-Nano“ (als Abkürzung für „LGT8F328P basiert“) und den „L-Pro Mini“ habe ich das großartige Board Paket lgt8fx von David Buezas verwendet. Es basiert auf Larduino_HSP und LGT ist aber einfacher handhabbar, nutzt die Vorteile des LGT8F328P besser und ist besser dokumentiert. Mehr zu den Unterschieden erfahrt ihr hier.
Eine detaillierte Installationsanleitung für das Board Paket mit Screenshots findet ihr hier. Die Kurzversion lautet:
- Geht auf Datei → Voreinstellungen.
- Klickt auf den Button hinter „Zusätzliche Boardverwalter-URLs“.
- Tragt dort die Zeile „https://raw.githubusercontent.com/dbuezas/lgt8fx/master/package_lgt8fx_index.json“ (ohne Anführungsstriche) ein.
- Navigiert zu Werkzeuge → Board: „xxx“ → Boardverwalter.
- Sucht nach „lgt8fx“ und installiert das Paket „LGT8fx Boards“ von dbuezas.
Nach erfolgreicher Installation wählt ihr als Board „LGT8F328“. Unter „Variant“ habe ich „328P-LQFP32 (e.g. MiniEVB nano-style or WAVGAT)“ ausgewählt.
UNO Style
Für das UNO Board von AZ-Delivery verfahrt ihr im Prinzip genauso. Der Eintrag für die Boardverwalter-URL lautet:
- http://www.az-arduino.de/package_AZ-Boards_index.json
Im Boardverwalter Menü sucht ihr nach „AZ-Boards“. Eine detaillierte Beschreibung gibt es im kostenlosen E-Book von AZ-Delivery.
Prüfung der Installation
Nehmt irgendeinen Sketch, beispielsweise Blink.ino aus den „Basics“ Beispielsketchen der Arduino IDE und ladet ihn hoch. Die Board-LED sollte im Sekundentakt blinken.
Wie ihr Sketche per USB-zu-TTL Adapter (z.B. für den Pro Mini) oder per LGTISP hochladet und den Bootloader brennt, erkläre ich gegen Ende des Beitrages (hier).
LGT8F328P-LQFP32 Boards in Action
Genug der Vorbereitungen und allgemeinen Erklärungen – jetzt kommen wir zum interessanteren, praktischen Teil.
Ich habe sehr viele Arduino Sketche mit unterschiedlichsten Funktionen unverändert auf den LGT8F328P Boards ausprobiert. Lediglich beim Watchdog Timer und bei den Sleep-Funktionen waren Anpassungen notwendig. Alles andere funktionierte 1:1. Im Wesentlichen können wir uns also auf die zusätzlichen Funktionen konzentrieren.
Analog-Digital Wandler
Ihr könnt, wie bei den ATmega328P basierten Boards, die Spannung an einem analogen Pin per analogRead()
auslesen. Die Voreinstellung für die Auflösung ist 10 Bit. Die Standard-Referenzspannung ist die Betriebsspannung.
Dabei ist zu beachten, dass das „Nano-like“ Board eine Diode zum Schutz des USB-Ports in der 5 Volt-Leitung verbaut hat. Die effektive Betriebsspannung liegt deshalb bei USB-Betrieb bei ca. 4.6 Volt. Ihr findet die Diode oberhalb der Pins D10 / D11.
Wie bei den herkömmlichen ATmega328P Boards könnt ihr externe Spannungsreferenzen verwenden. Ihr schließt sie an den Eingang REF an. Alternativ stellt der LGT8F328P interne Referenzen von 1.024, 2.048 oder 4.096 Volt zur Verfügung. Überdies erlaubt euch der LGT8F328P, die Auflösung auf 11 oder 12 Bit zu erhöhen. Der folgende Sketch zeigt, wie es geht:
/* Parameter: Reference: DEFAULT VCC EXTERNAL External Reference (REF) INTERNAL1V024 Internal 1.024 volts INTERNAL2V048 Internal 2.048 volts INTERNAL4V096 Internal 4.096 volts */ void setup(){ Serial.begin(9600); analogReference(INTERNAL4V096); analogReadResolution(10); // Resolution = 10, 11 or 12 Bit } void loop(){ int adcValue = analogRead(A1); // Raw value float voltage = adcValue * 4.096/1024.0; // Voltage calculation Serial.print("Analog Value: "); Serial.println(adcValue); Serial.print("Voltage [V]: "); Serial.println(voltage,3); delay(1000); }
Qualität des AD-Wandlers
Die gute Nachricht: Der AD-Wandler des LGT8F328P arbeitet ziemlich linear. Die schlechte Nachricht: Das Rauschen ist mindestens so schlecht wie bei den AVR basierten Boards. Selbst in der 10 Bit Auflösung musste ich mindestens 100 Messwerte mitteln, um stabile Werte zu erhalten. Da nützt einem eine 11- oder 12-Bit Auflösung leider herzlich wenig! Evtl. lässt sich das Rauschen noch durch Stabilisierung der Versorgungsspannung senken, da muss ich noch mal ein wenig experimentieren.
Konzentrieren wir uns auf das Positive. Ich habe den AD-Wandler geprüft, indem ich mit meinem Labornetzteil Spannungen vorgegeben und mit dem LGT8F328P gewandelt habe. Die Spannungen habe ich mit einem zuverlässigen Multimeter überprüft. Bei der A/D-Wandlung kam die interne 4.096 Volt Referenz zum Einsatz und je 100 Messwerte wurden gemittelt. Die Messung habe ich mit verschiedenen Boards durchgeführt. Hier ein typisches Ergebnis:
Jedes Board hatte eine individuelle, geringe und reproduzierbare Abweichung. Wer es genau braucht, der könnte sich also mit Excel o. ä. eine Ausgleichsfunktion erstellen.
Analoge Differenzmessungen und Verstärkung
Der LGT8F328P ermöglicht euch Differenzmessungen zwischen bestimmten analogen Eingängen. Die Differenzspannungen könnt ihr 1-, 8-, 16- oder 32-fach verstärken. Die Funktion dazu lautet analogDiffRead()
. Sie erwartet als Argumente den negativen Eingang, den positiven Eingang und den Verstärkungsfaktor. Um die Funktion nutzen zu können, müsst ihr die Bibliotheksdatei differential_amplifier.h einbinden.
Hier ein Beispiel:
#include<differential_amplifier.h> /* Parameter: Reference: DEFAULT VCC EXTERNAL External Reference (REF) INTERNAL1V024 Internal 1.024 volts INTERNAL2V048 Internal 2.048 volts INTERNAL4V096 Internal 4.096 volts Available combinations: | -\+ | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | A0 | | + | | | | | | | | A1 | + | | | | | | | | | A2 | + | + | | + | + | + | + | + | | A3 | + | + | + | | + | + | + | + | | A4 | + | + | | | | | | | | A5 | + | + | | | | | | | | A6 | + | + | | | | | | | | A7 | + | + | | | | | | | */ void setup(){ Serial.begin(9600); analogReference(INTERNAL4V096); } void loop(){ int raw = analogDiffRead(A2,A3,GAIN_16); // GAIN_x mit x = 1, 8, 16, 32 float voltage = raw / 1024.0 * 4096.0 / 16.0; // considers resolution, reference and gain Serial.println(voltage); delay(1000); }
Wie ihr an der Tabelle im Sketch seht, sind nur bestimmte Kombinationen analoger Eingänge erlaubt. Wählt ihr eine unzulässige Kombination, erhaltet ihr als Rohwert -1.
Die Dokumentation zur Differential Amplifier Bibliothek findet ihr hier.
Um differential_amplifier.h mit dem LGT8F328P basierten UNO von AZ-Delivery zu nutzen, ladet ihr euch am einfachsten das Paket lgt8fx von hier herunter und extrahiert die entsprechenden „.cpp“- und „h.“-Dateien aus dem Ordner lgt8f/libraries/differential_amplifier und speichert sie Ordner des Sketches. Bei der #include
Anweisung müsst ihr die Bibliotheksdatei in Anführungsstriche setzen.
Digital-Analog Wandler
„Quasi-analoge“ PWM Signale
Wie von den ATmega328P Boards gewohnt, könnt ihr mit analogWrite()
an den (Arduino) Pins 3, 5, 6, 9, 10 und 11 ein PWM-Signal abgreifen. Ebenso ist die PWM-Frequenz an den Pins 5 und 6 doppelt so hoch wie an den anderen Pins. Zu beachten ist, dass die Frequenzen von der Taktrate abhängen. Bei 16 MHz entsprechen sie mit 490 bzw. 980 Hertz denen der ATmega328P Boards. Der Wert ändert sich proportional mit der Taktrate.
Wie ihr an den Pins 1 (TX) und 2 (D2) PWM Signale erzeugt, erkläre ich, wenn wir zu den Timern kommen. Einige Pinout Schemata, die man im Netz findet, weisen zusätzlich den Pin 8 als PWM Pin aus. Das ist jedoch falsch.
Ein echtes analoges Signal erzeugen
Am Pin 4 (D4 / PD4 / DAO) könnt ihr ein echtes analoges Signal mit einer Auflösung von 8 Bit einstellen. Standardmäßig ist VCC die Referenz, sprich 255 ≙ VCC. Alternativ könnt ihr eine externe Referenz oder die internen Referenzen 1.024, 2.048 oder 4.096 Volt nutzen. Der folgende kleine Sketch zeigt, wie es funktioniert:
/* Parameter: Reference: DEFAULT VCC EXTERNAL External Reference (REF) INTERNAL1V024 Internal 1.024 volts INTERNAL2V048 Internal 2.048 volts INTERNAL4V096 Internal 4.096 volts */ void setup(){ analogReference(DEFAULT); pinMode(DAC0, ANALOG); analogWrite(DAC0, 125); // 0...255 } void loop(){}
Genauigkeit des DAC
Ich habe die Genauigkeit des analogen Signals unter Verwendung der 4.096 Volt Referenz überprüft und war von der Übereinstimmung zwischen kalkulierten und gemessenen Wert ziemlich beeindruckt:
80 mA Ausgänge nutzen
Wegen der Doppeldeutigkeit der unterschiedlichen Pinbezeichnungen (z.B. 1 vs. TX vs. PD1 vs. D1) verwende ich im Folgenden die Bezeichnungen auf dem LGT8F328P Nano Board, wenn ich mich auf die Boardpins beziehe.
Die Pins TX, D2, D5 und D6 sind bis zu 80 mA belastbar. Allerdings müsst ihr diese „Hochstrom“-Funktion erst aktivieren, indem ihr die entsprechenden Bits im HDR Register setzt. Dann könnt ihr – jedenfalls für die Pins D5 und D6 – die Ausgänge mit pinMode()
und digitalWrite()
nutzen. Hier ein Beispiel:
/* HDR Port/Pin Pin Label (Nano) HDR0 --> PD5 --> D5 HDR1 --> PD6 --> D6 HDR2 --> PF1 --> TX HDR3 --> PF2 --> D2 HDR4 --> PE4 / PF4 --> none HDR5 --> PE5 / PF5 --> none */ void setup(){ HDR |= (1<<HDR0); // Activate high current for Pin 5 pinMode(5,OUTPUT); digitalWrite(5, HIGH); } void loop(){}
Wenn ihr die 80 mA Option an den Pins TX und D2 aktivieren wollt, dann gibt es eine kleine Komplikation. PD1 und PF1 teilen sich TX, PD2 und PF2 teilen sich D2 (was eine eindeutige Benennung der Pins noch schwieriger macht). Die Hochstromoption wird aber nur an PF1 und PF2 bereitgestellt und nicht an PD1 oder PD2. Da aber PF1 und PF2 nicht als Arduino Pins implementiert sind (beim QFP32L), müsst ihr sie direkt über die Ports ansprechen. Hier ein „Hochstrom-Blink-Sketch“ für PF2:
/* HDR Port/Pin Pin Label (Nano) HDR0 --> PD5 --> D5 HDR1 --> PD6 --> D6 HDR2 --> PF1 --> TX HDR3 --> PF2 --> D2 HDR4 --> PE4 / PF4 --> none HDR5 --> PE5 / PF5 --> none */ void setup(){ /* example for activating PF2 for high current */ HDR |= (1<<HDR3); DDRF = (1<<PF2); // ~ pinMode OUTPUT } void loop(){ PORTF |= (1<<PF2); // Pin HIGH delay(1000); PORTF &= ~(1<<PF2); // Pin LOW delay(1000); }
Aber hier ist Vorsicht geboten: Wenn PF1 oder PF2 sich im Zustand OUTPUT / HIGH befinden und PD1 bzw. PD2 auf OUTPUT / LOW könntet ihr einen Kurzschluss verursachen (ausprobiert habe ich es nicht). Und PD1 könntet ihr versehentlich über seine TX-Funktion in diesen Zustand bringen.
Falls ihr euch mit Bitoperationen und Portmanipulationen wie beispielsweise PORTF &= ~(1<<PF2)
nicht auskennt, empfehle ich meinen Beitrag zu diesem Thema.
Watchdog Timer (WDT)
Vielleicht hat der/die eine oder andere meinen Beitrag über den Watchdog Timer des ATmega328P gelesen. Die Sketche funktionieren auf den LGT8F328P Boards nur eingeschränkt. Wenn ihr den WDT verwenden wollt, dann nutzt ihr am besten die im Board Paket lgt8fx enthaltene Bibliothek WDT (anstelle avr/wdt.h). Hier ein Beispielsketch:
/* Parameter WDT Reset Period WTO_64MS 64 ms WTO_128MS 128 ms WTO_256MS 256 ms WTO_512MS 512 ms WTO_1S 1 s WTO_2S 2 s WTO_4S 4 s WTO_8S 8 s WTO_16S 16 s WTO_32S 32 s */ #include <WDT.h> void setup() { Serial.begin(9600); Serial.println("Sketch started"); wdt_enable(WTO_8S); } void loop() { for(int i=0; i<1000; i++){ Serial.print("Runtime [s]: "); Serial.println(i); delay(1000); // wdt_reset(); } }
Nach jeweils acht Sekunden wird ein Neustart ausgelöst. Wenn ihr jedoch die Zeile 28 entkommentiert, läuft der Sketch durch.
WDT Interrupt
Um die WDT ISR zu nutzen, verwendet ihr die Funktion wdt_ienable(). Hier ein Beispiel:
#include <WDT.h> volatile boolean isrflag; void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); Serial.begin(9600); Serial.println("Sketch started."); isrflag = false; wdt_ienable(WTO_4S); } void loop() { int n = 0; do { Serial.print("Elapsed time: "); Serial.print(n); Serial.println(" s"); delay(1000); if (digitalRead(LED_BUILTIN)) digitalWrite(LED_BUILTIN, LOW ); else digitalWrite(LED_BUILTIN, HIGH); if (isrflag) { Serial.println("--There was a wdt interrupt.--"); isrflag = false; wdt_enable(WTO_4S); // uncomment this line... // wdt_ienable(WTO_4S); // ...comment this line and see the change } // wdt_reset(); // if uncommented, no interrupt will occur } while( n++ < 1000 ); } ISR (WDT_vect) { isrflag = true; wdt_reset(); }
Wenn ihr den LGT8F328P nach dem Interrupt nicht neu starten wollt, dann wechselt in Zeile 28/29 von wdt_enable() auf wdt_ienable().
Schlaf- und Power-Modi
Wenn ihr euer LGT8F328P Board in den Schlaf schicken wollt, dann nutzt ihr am besten die im Board Paket enthaltene Bibliothek PMU.
Um den folgenden Beispielsketch auszuprobieren, verbindet ihr Pin 2 (D2) über einen Taster mit GND. Mit den im Sketch gewählten Einstellungen wird euer Board in den Schlaf geschickt, wacht nach vier Sekunden wieder auf, um dann wieder in den Schlaf geschickt zu werden usw. Drückt ihr den Taster, wacht euer Board durch den externen Interrupt sofort auf.
/* Power Modes PM_IDLE0: disable core clock only PM_POWERDOWN: disable most clocks and switch main clock to rc32k PM_POFFS0: power off all core functions (digital and analog) wake up by external interrupt or periodly PM_POFFS1: the lowest power mode which close all modules and clocks wake up by external interrupt only Sleep Duration: SLEEP_xMS with x = 64, 128, 256, 512 (milliseconds), e.g. SLEEP_256MS SLEEP_yS with y = 1, 2, 4, 8, 16, 32 (seconds), e.g. SLEEP_4S SLEEP_FOREVER */ #include <PMU.h> const int interruptPin = 2; void setup(){ Serial.begin(9600); Serial.println("Sketch started!"); pinMode(interruptPin, INPUT); digitalWrite(interruptPin, HIGH); attachInterrupt(digitalPinToInterrupt(interruptPin), noAction, FALLING); } void loop(){ Serial.flush(); PMU.sleep(PM_POWERDOWN, SLEEP_4S); Serial.println("Woke Up!"); delay(200); // for debouncing } void noAction(){} // dummy
Fastio – Funktionen
Die Funktionen pinMode()
, digitalWrite()
und digitalRead()
haben eine ganze Menge Ballast, den man in den meisten Fällen nicht braucht. Wenn ihr ein paar Mikrosekunden einsparen wollt, dann könnt ihr die schon erwähnte Portmanipulation anwenden. Wem das zu kryptisch ist, dem stehen fastioMode()
, fastioWrite()
, fastioRead()
und fastioToggle()
als Alternativen zur Verfügung.
Der Nachteil an den Funktionen ist, dass ihr ihnen keine Variablennamen übergeben dürft, sondern nur die Pinnummer. Versucht ihr es trotzdem, hagelt es Fehlermeldungen.
Hier ein Beispiel für den korrekten Gebrauch:
void setup() { fastioMode(8, OUTPUT); // equals: DDRB |= (1<<PB0); } void loop() { fastioWrite(8, HIGH); // equals (in essence): PORTB |= (1<<PB0); delay(100); fastioWrite(8, LOW); // equals (in essence): PORTB &= ~(1<<PB0); delay(100); fastioToggle(8); // equals: PINB = (1 << PB0); delay(1000); fastioToggle(8); // equals: PINB = (1 << PB0); delay(1000); }
Die Verwendung von fastioRead()
ist genauso einfach:
int status = fastioRead(8); // equals: int status = (PINB >> PB0) & 1;
Die fastio-Funktionen sind kein besonderes Merkmal des LGT8F32P, sondern nur ein nettes Feature des Board Paketes.
Timer und PWM
Der LGT8F328P besitzt zwei 8-Bit und zwei 16-Bit Timer, also einen 16-Bit Timer mehr (Timer3) als der ATmega328P. Zu den Timern 0 bis 2 gehören je zwei Output Compare Register, mit deren Hilfe ihr an den zugeordneten Ausgängen OCxA/OCxB PWM Signale erzeugen könnt. Wie das funktioniert, habe ich in meinen Beiträgen über die Timer0 und Timer1 und über den Timer2 erklärt. Alle dort verwendeten Sketche funktionieren auch auf dem LGT8F328P.
Zum Timer3 gehören drei Output Compare Register und die drei Ausgänge OC3A, OC3B und OC3C.
Das Pinoutschema des LGT8F328P-QFP32L (siehe ganz oben) ist diesbezüglich etwas irreführend. Richtig ist, dass OC3C keinen Ausgangspin hat. Ebenso stimmt, dass OC3A und OC3B an den Pins für PD1 und PD2 ausgeführt sind. Um ein PWM Signal auszugeben, müsst ihr allerdings PF1 und PF2 auf OUTPUT setzen. PF1 und PF2 teilen sich, wie schon erwähnt, ihre Ausgänge mit PD1 und PD2.
Hier ein Beispiel für ein Fast PWM Signal an PF1 (Board Pin: TX) mit einem Duty Cycle von 25 % und einer PWM-Frequenz von 2 kHz (wenn der LGT8F328P auf 32 MHz läuft):
void setup(){ // Clear OC3A on Compare Match / Set OC3A at Bottom; Wave Form Generator: Fast PWM 14, Top = ICR3 TCCR3A = (1<<COM3A1) + (1<<WGM31); TCCR3B = (1<<WGM33) + (1<<WGM32) + (1<<CS30); // prescaler = 1; ICR3 = 15999; OCR3A = 3999; DDRF |= (1<<PF1); } void loop() {}
Weitere Erklärungen würden hier zu weit führen – bei Interesse schaut in die schon erwähnten Beiträge über die Timer des ATmega328P. Oder, wer keine Lust hat zu rechnen und sich die ganzen Bits aus den Tabellen herauszusuchen, mag vielleicht dieses tolle Tool von David Buezas ausprobieren: Arduino Web Timers. Die Dokumentation dazu gibt es hier auf GitHub.
Ihr könnt den Timer0 und Timer1 Counter übrigens auch auf die doppelte Systemfrequenz einstellen, also auf bis zu 64 MHz! Dazu müsst ihr im „Timer Counter Clock Control und Status Register“ (TCKCSR) das F2XEN-Bit setzen. Durch Setzen der Bits TC2XS0 für Timer0 bzw. TC2XS1 für Timer1 teilt ihr dem LGT8F328P mit, welcher Timer auf doppelter Geschwindigkeit laufen soll. Also z.B.:
TCKCSR = (1 << F2XEN) | (1 << TC2XS0);
Ein Grund mehr, das Tool von David Buezas einzusetzen.
Den LGT8F328P basierten Pro Mini programmieren
Upload per USB-zu-TTL Adapter
Dem Pendant zum Arduino Pro Mini („L-Pro Mini“) fehlt, genau wie dem Original, der USB-zu-TTL Adapter. Ihr braucht also einen solchen als externes Modul. Die Programmierung ist am bequemsten, wenn ihr einen Adapter mit DTR Pin nehmt.
Der hier abgebildete Adapter hat zudem den Vorteil, dass ihr ihn direkt auf den „L-Pro Mini“ stecken könnt, sofern ihr zuvor eine Pinleiste aufgelötet habt.
Solltet ihr hingegen alles per Kabel zusammenstecken, müsst ihr darauf achten, dass ihr RX mit TX und TX mit RX verbindet.
Der Upload ist einfach: Wählt den Port aus, an dem euer Adapter hängt und dann einfach hochladen.
Falls ihr einen USB-zu-TTL Adapter ohne DTR-Pin habt, ist es ein kleines bisschen komplizierter. Wenn ihr den Hochladevorgang einleitet, dann drückt ihr auf die Reset-Taste des zu programmierenden Boards. Lasst die Taste los, wenn die Kompilierung beendet ist und das eigentliche Hochladen starten soll.
Upload per LArduinoISP (ohne Bootloader)
Wie wir schon gesehen haben, weist der LGT8F328P bei aller Kompatibilität mit dem ATmega328P „unter der Haube“ deutliche Unterschiede auf. Das zeigt sich auch darin, dass er nicht über seine Pins 11, 12 und 13 per ISP programmierbar ist. Stattdessen besitzt er zu diesem Zweck die Pins SWC und SWD.
Aber wie beim ATmega328P, könnt ihr auch ein LGT8F328P basiertes Board zu einem ISP Programmer umfunktionieren.
Für den „LGT8F328P – UNO“ von AZ-Delivery macht das wenig Sinn, da dieses Board den SWC und SWD-Pin nicht ausgeführt hat.
Ein LGT8F328P Board zum Programmer machen
Ihr nehmt das LGT8F328P basiertes Board, das als Programmer dienen soll und verbindet es mit eurem Rechner. Schließt am besten nichts weiter an das Board an. Dann führt ihr die folgenden Schritte aus:
- Wählt in der Arduino IDE das angeschlossene Board aus.
- Unter Werkzeuge → „Arduino as ISP“ stellt ihr die Option „[To burn an ISP] SERIAL_RX_BUFFER_SIZE to 250“ ein (s.u., blaue Auswahl).
- Geht im Menü auf Datei → Beispiele → „Beispiele für LGT8F328“ und wählt dort den Sketch LarduinoISP aus.
- Ladet den Sketch hoch.
- Stellt „Arduino as ISP“ in den Werkzeugen wieder zurück auf Default (64).
Fertig ist der Programmer!
Sketche hochladen
Nehmt euren Programmer und verbindet ihn wie folgt mit dem zu programmierenden Board („Target“):
Programmer | Target |
GND | GND |
5V | VCC |
Pin 12 (D12) |
SWD |
Pin 10 (D10) |
RST |
Pin 13 (D13) |
SWC |
Um beim Upload auf das Target einen Reset des Programmers zu verhindern, verbindet ihr den RST-Pin des Programmers über einen 10 µF Kondensator mit dem 5 V Pin. Notfalls könnt ihr die beiden Pins auch direkt verbinden, dann dürft ihr aber keinesfalls den Reset-Knopf des Programmers drücken (Kurzschluss!).
So sieht das Ganze beispielsweise mit einem „L-Nano“ als Programmer und einem „L-Pro Mini“ als Target aus:
Wählt die folgenden Einstellungen in der Arduino-IDE:
- Als Board wählt ihr das Target-Board aus.
- Unter Werkzeuge → Programmer wählt ihr „AVR ISP“.
Zum Hochladen geht ihr dann auf Sketch → Hochladen mit Programmer oder ihr verwendet die Tasten-Kombi: Strg + Umschalt + U.
Den Bootloader zurückbringen
Wenn ihr einen Sketch per LarduinoISP hochgeladen habt, dann ist der Bootloader gelöscht. Um das Board wieder direkt per USB bzw. USB-zu-TTL Adapter programmieren zu können, müsst ihr den Bootloader zurückbringen. Nichts einfacher als das: Verwendet dieselben Einstellungen wie beim Hochladen per LarduinoISP-Programmer und geht auf Werkzeuge → Bootloader brennen.
Probleme mit dem lilafarbenen LQFP32 Board als LArduinoISP Programmer
Das lilafabene LQFP32 Board mit dem CH9340C USB-zu-TTL Chip lässt sich aus mir bisher nicht bekannten Gründen nicht als LArduinoISP Programmer einsetzen.
Fazit
LGT8F328P basierte Boards sind eine leistungsstarke Alternative zu ihren ATmega328P Pendants. Dank der verfügbaren Board Pakete sind die LGT8F328P Boards einfach zu handhaben. Sketche, die ihr für die ATmega328P Boards geschrieben habt, sind mit wenigen Ausnahmen direkt übertragbar. Dazu bietet der LGT8F328P einige zusätzliche, sinnvolle Features.
Danksagung
Ich danke David Buezas, LaZsolt und dwillmore für die hervorragende Arbeit an dem Board Paket lgt8fx und für das Review dieses Artikels.
Hallo,
danke für die ausführliche Behandlung dieser MCU . Die LGT8F328P – basierten Boards sind schon seit Jahren der Standard für meine Projekte. Aus meinen Experimenten noch folgende Beobachtungen :
– der interne Oszillator lässt sich auf ca.40 MHz per Software übertakten – das Register heisst RCMCAL.
– ebenso können die Referenzspannungen in einem weiten Bereich angepasst werden (VCAL)
– der maximale Wert , den der ADC ausgibt, ist 4063 (0x0FDF) statt 4095. Da die Auflösung 12 bit ist, fehlen also die letzten 32 codes vor full range. Das führt schon mal zu unerwarteten Ergebnissen.
-das SPI Modul hat für beide Datenrichtungen einen 4 byte FIFO und damit wesentlich bessere Performance als die Atmegas.
– Eine weitere Abweichung vom AVR-Vorbild ist, dass der Flash-Speicher aus dem laufenden Programm beschrieben und in 1 kB pages gelöscht werden kann. Man kann also EEPROM -ähnliche Funktionen direkt programmieren, ohne den „EEPROM-Simulator“ (Hardware, führt bei jedem Schreibvorgang einen page swap/erase aus) benutzen zu müssen.
Rätselhaft auch die Tatsache, dass die Chips in allen Gehäuseformen keine Typ- oder Herstellerbezeichnung haben – irgend eine Idee, warum ?
Auch wenn die Architektur und die Performance des LGT8F328P nicht mehr „leading edge“ sind , schätze ich speziell die flexiblen Schnittstellen und Analogfunktionen . Vielen Dank nochmal für die exzellente Darstellung.
Viele Grüße
Georg Grossmann
Hallo Wolfgang, toller Artikel, vielen Dank! Ich habe 30 Stück aus China bekommen zu je 1,50€ etwa. Eine wirkliche Alternative zu den aktuellen Preisen des 328p!
PS: genau waren es 49,40€, versandkostenfrei für die 30 Stück, also 1,66€ das Stück. Aktuell liegt der Preis bei dem Verkäufer bei etwa 2€.
Ist schon wahnsinnig, dass sich eine Produktion für solche Preise lohnt!
Hallo Wolfgang, eine Frage zum Thema ‚Ein LGT8F328P Board zum Programmer machen‘: Kann ich auch z.B. ein UNO Board zum Programmer machen?
Mein Problem: getreu dem Motto ‚erst probiert, dann studiert‘ habe ich versucht mein LGT8F328P Board als Arduino Nano zu flashen – das hat vermutlich den Bootloader zerstört. Könnte ich also mit der von dir beschriebenen Methode versuchen den Bootloader zu restaurieren? Habe im Moment nur ein LGT Board aber einige UNOs.
Übrigens finde ich Deine Website sehr schön und informativ gemacht! Danke dass Du dein Wissen teilst.
Hallo, ich hätte gar nicht gedacht, dass man das LGT8F328P Board überhaupt „erreicht“, wenn man als Board den Arduino Nano eingestellt hat. Aber ich habe es eben selbst mal ausprobiert und ich konnte tatsächlich einen Blinksketch hochladen. Erläuft dann nur zu langsam. Danach habe ich wieder auf den LGT8F328P umgestellt und konnte immer noch Sketche hochladen. Also ist der Bootloader nicht zerstört, weswegen sich die Frage stellt, ob vielleicht irgendetwas anderes im Argen liegt. Könntest du noch einmal genauer beschreiben, welches Board du genau einsetzt (LQF32 MiniEVB)? Und was sind die Einstellungen in der Arduino IDE, insbesondere Board, Clock Source, Upload Speed und Variant? Und – letzte Frage – was genau ist die Fehlermeldung beim Versuch Sketche hochzuladen?
Und ja, wenn alles nicht hilft, dann würde ich mal versuchen, den Bootloader neu zu brennen. Allerdings brauchst du dafür ein zweites LGT8F328P Board. Bei Amazon bekommt man die Dinger im Doppelpack für 10,50 Euro. Ich möchte nicht ausschließen, dass es auch irgendwie mit dem UNO geht, aber ich selbst habe es nicht probiert.
Hallo Wolfgang, ich verwende ein LQFP32 MiniEVB mit dem CH340 chip drauf (das lilafarbene).
Einstellungen: Board: LGT8F, ClockSource: Internal 32MHz, Divider: 16, Variant: … WAVGAT, BUFFER_SIZE: 64, Upload speed: 57600
Fehlermeldung:
Der Sketch verwendet 6958 Bytes (23%) des Programmspeicherplatzes. Das Maximum sind 29696 Bytes.Globale Variablen verwenden 532 Bytes (25%) des dynamischen Speichers, 1516 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
avrdude: stk500_paged_write(): (a) protocol error, expect=0x14, resp=0x94
avrdude: stk500_cmd(): programmer is out of sync
avrdude: loadaddr(): (b) protocol error, expect=0x14, resp=0x00
avrdude: stk500_paged_load(): (a) protocol error, expect=0x14, resp=0x10
avrdude: stk500_cmd(): protocol error
avr_read(): error reading address 0x0000
read operation not supported for memory „flash“
avrdude: failed to read all of flash memory, rc=-2
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x0c
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x0c
Ich habe mir inzwischen nochmal so ein Board bestellt sowie eins mit dem HT42 drauf (grün)
Werde berichten, ob das mit dem Bootloader brennen funktioniert hat
Ist mir bisher nicht über Weg gelaufen, das Problem. Bootloader brennen hilft vielleicht. Das würde ich auch auf jeden Fall probieren. Wenn das nicht hilft, dann kannst du mir auch gerne so ein Teil zuschicken. Würde ich mir gerne mal anschauen. VG, Wolfgang
So, ich habe jetzt meine neuen LGT8Fs bekommen und gleich probiert: Bootloader neu geflasht und anschliessend einen Testsketch: Verhalten hat sich nicht geändert, gleiche Fehlermeldung. Kleinere Sketche scheinen aber trotz der Fehlermeldung zu laufen (z.B. AnalogReadSerial) Wenn ich in die neuen Boards eine SW flashe tritt keine Fehlermeldung auf.
Sehr merkwürdig, vielleicht hast du einfach Pech gehabt und eine Fehlcharge erwischt. Was auch immer zu diesen Fehlermeldungen führen mag. Immerhin funktioniert es ja mit den neuen Boards.
Hallo Wolfgang,
vielen Dank für den hilfreichen Artikel.
Habe mir vor geraumer Zeit einen Nano mit diesem Chip zugelegt ohne den Unterschied zu bemerken.
Jetzt in der Verwendung fiel mir auf, dass die Ausgabe auf den Seriellen Monitor der 2.2 IDE unter Linux
nicht lesbar war. Der Serielle Loopback Test lief fehlerfrei. Dank Deines Artikel habe ich den passenden
Board Manager eingestellt und siehe da, die Ausgabe auf dem Seriellen Monitor war lesbar.
Viele Grüße!
Michael
Schön, dass der Artikel geholfen hat – viele Dank fürs Feedback!
VG, Wolfgang
Hallo Wolfgang,
wo beziehst Du eigentlich die LGT8F328P IC’s. Habe schon einige Händler abgegrast, leider ohne Erfolg. Ein Hinweis wäre toll, passende Boards habe ich…
VG Frank
Hallo Frank,
ja, das Angebot ist übersichtlich. Auf AliExpress gibt es sie, z.B. hier:
https://a.aliexpress.com/_mN22RzM
Ein paar Wochen Lieferzeit muss man allerdings in Kauf nehmen.
VG, Wolfgang
Hallo Wolfgang,
vielen Dank für Deine schnelle Antwort und den Hinweis / Link zu Aliexpress.
Ebenfalls ein dickes Lob für Deine tollen Artikel über diesen Controller !!!
Grüße Frank
Hallo,
super Artikel !
hab vor einigen Jahren mit dem lgt8f experimentiert, war aber noch nicht so begeistert, da auch die SW wohl noch auf anderem Stand war.
Hab das Ding heute hervorgekramt und mal den ADC getestet.
Scheint ca 4,5 x so schnell wie der NANO zu laufen, unabhängig von der Auflösung (10,11,12 bit) , was mich etwas wundert, aber vielleicht mach ich da noch was falsch.
Was schön wäre, wenn man auf ihm auch den OptiBoot installieren könnte, nich so sehr wegen der Schnelligkeit, sondern wegen des geringeren Platzbedarfs .
Kalle
Also ich bin mir nicht sicher, ob Sie in einigen Dingen nicht etwas voreilig waren:
„Wie der ATmega328P hat er … einen EEPROM von 1 KB.“
Nach dem ich das Datenblatt studiert habe und mich im Netz umschaute, scheint der lgt8f328p überhaupt keinen EEPROM zu haben. [1] Es scheint sich eher um eine Möglichkeit zu handeln, den FLASH als ROM zu „gebrauchen“, was einige als EZPROM bezeichnen. [2]
„Das Pinout Schema des QFP32L zeigt viele Übereinstimmungen mit dem des ATmega328…“
Hier wäre es ratsam gewesen, neben dem lgt8f328p auch den ATmega328p als Pinout abzubilden/gegenüber zu stellen. Dann fallen weitere Unterschiede auf.
Persönlich möchte ich hinzu fügen:
Um so mehr ich mich mit dem lgt8f328p auseinander setzt, um so deutlicher werden die Unterschiede und mir scheint es so, als handelt es sich beim lgt8f328p um kein anders gearteter Nachbau, sondern möglicherweise um eine Eigenentwicklung der Chinesen. Das geht schon beim Debugging weiter …
[1] https://forum.arduino.cc/t/trouble-accessing-eeprom-with-an-lgt8f328p-nano-clone/1114780
[2] https://www.jarutex.com/index.php/2021/10/09/6742/
Absolut richtig – der LGT8F328P ist kein Nachbau, sondern ein Eigenentwicklung. Sonst liefe er nicht auf 32 MHz, hätte nicht die Ports E und F, würde keine 80 Milliampere an ausgewählten Ausgängen zur Verfügung stellen, hätte keinen Timer3, keine analogen Differenzmessungen und und und…
Allerdings ist es eine Entwicklung, die darauf ausgelegt ist, eine recht weitgehende Kompatibilität mit dem ATmega328P zu gewährleisten, was besonders für die QFP32L Ausfertigung gilt. Und das ist ziemlich gut gelungen.
Der Beitrag hat keinen Anspruch auf Vollständigkeit. Natürlich gibt es noch mehr Unterschiede, auf die ich zum Teil im nächsten Beitrag eingehe, z.B. alternative PWM Ausgänge, Schlafmodi, Strombedarf. Aber selbst dann werde ich bei weitem nicht alles erfasst haben.
Zum EEPROM: stimmt, der EEPROM ist keiner, sondern eine Art Emulation eines EEPROM, die auf Kosten des Flash geht und das sogar doppelt, denn 1 kB „EEPROM“ kostet 2 kB Flash. Wer viel macht, macht auch Fehler – Danke für den Hinweis!
Das Debugging werde ich mir auch noch mal anschauen – Danke auch dafür.
Ich finde Ihre Art mit Kritik umzugehen sehr gelungen und bedanke mich aufrichtig für Ihren Artikel und diese Stellungnahme.
Hallo Wolfgang,
hier ein paar meiner Erfahrungen mit den LGT8F328P – LQFP32 Nano style Boards, die haben bei mir die Nano Clone fast vollständig abgelöst.
Der Stromverbrauch im Betrieb unterscheidet sich zwischen dem Grünen und dem Purple Boards deutlich, das Purple ist sparsammer ( 18 zu 11 mA @16 MHz).
Im vergleich zu meinen Nano Clonen ist der ADC des LGT8F328P deutlich schneller. Auch beim ADC habe ich stabilere Werte bei den Purple Boards, – was aber auch Zufall sein könnte, ich habe da noch keinen Reihentest gemacht…
Gruß
Herbert
Hallo Herbert,
vielen Dank für das Teilen deiner Erfahrungen. Das mit dem ADC, also purple vs. green muss ich mal ausprobieren.
Mit dem letzten Release des Boardpaketes 2.0.4 kam noch die Bibliothek lgt_LowPower hinzu. Und dazu gibt einen Beispielsketch adcNoiseReduction. Hab ich noch nicht ausprobiert, klingt aber vielversprechend.
VG, Wolfgang
Danke für die hervorragende Analyse.
Wie ist der Stromverbrauch?
Hallo,
Über den Stromverbrauch der Boards wird hier berichtet:
https://github.com/dbuezas/lgt8fx#power-consumption–5v
Über den Stromverbrauch der blanken Chips kann ich (noch) nichts sagen. Die Macher des Boardpaketes sind dabei, eine LOW Power Bibliothek zu schreiben. Da muss man noch ein bisschen abwarten.
Kurzes Update zum Stromverbrauch: siehe meine letzte Antwort zum Kommentar von Bernhard.
VG, Wolfgang
Hallo Wolfgang,
diese Chips sehen ja interessant aus! Allerdings scheint der Ruhestrom im Sleep-Modus ja ziemlich hoch zu sein, wenn man den Angaben in andern Blogs glauben kann. Damit scheiden sie dann für meine Anwendungen leider aus.
Grüße
Bernhard
P.S.: Bei AliExpress findet man aber 100% kompatible Klone des 328PU für rund €2,50, die als Original verkauft werden (siehe auch: https://hinterm-ziel.de/index.php/de/2023/03/07/atmega328p-original-oder-falschung/).
Vielen Dank.
Zusatz info: Die Entwickler des Boardpaketes arbeiten derzeit an einer LowPower Bibliothek. Wenn die veröffentlicht wird, werde ich auf das Thema Stromverbrauch noch einmal zurückkommen. Die blanken Chips gibt es ab 1,36€.
VG, Wolfgang
Hallo Bernhard,
wie angekündigt komme ich auf das Thema Stromverbrauch zurück. Im wachen Zustand verbraucht das lilafarbene LQFP32 „Nano style“ LGT8F328P Board bei 16 MHz 11.4 mA, wenn man es direkt über den 5 Volt Eingang speist. Unter denselben Bedingungen verbraucht ein Arduino Nano (mit ATmega328P, 5 V) 22 mA.
Zum Sleep. Hier sind die Modi nicht 1:1 vom ATmega328P übertragbar. Außerdem gibt es einige Randbedingungen zu beachten. Details finden sich hier: https://github.com/dbuezas/lgt8fx/tree/master/lgt8f/libraries/lgt_LowPower .
Da ich die blanken LGT8F328P Chips noch nicht erhalten habe, habe ich ein „Pro Mini style“ LQFP32 MiniEVB Board genommen und die LEDs und den Spannungsregler entfernt. Damit habe ich ermittelt:
Wachmodus, 5 V, 32 MHz: 11.2 mA
Idle Modus: 2.2 mA
Power-Down, Standby: 14.5 µA
Extended Standby: 23 µA
Deep Sleep: 1.1 µA
Durch Absenken der Betriebsspannung, was beim LGT8F328P ohne Einschränkung der maximalen Taktfrequenz möglich ist, lassen sich die Werte noch weiter herunterbringen.
Im nächsten Beitrag gehe ich auf die verschiedenen MiniEVB Boards einschließlich des Stromverbrauchs näher ein.
VG, Wolfgang