Ich stelle meinen alten Lenovo IdeaCenter B500 gerade auf Linux um. Dazu möchte ich parallel zum Win10 verschiedene schmale Linux-Distributionen testen. Das es bei dieser alten Hardware und DVD-Bootmedium Stunden dauert ein System aufzuspielen möchte ich laufende Testsysteme auf einer externen USBHDD speichern.

Chatgpt.com hat mir dazu folgenden Anleitung geliefert:

Perfekt! Ich schreibe dir eine klare Schritt-für-Schritt-Anleitung, wie du nur dein Linux-Mint-System aus einem Dualboot auf eine externe USB-HDD sichern kannst und später wieder zurückspielst. Sie ist so strukturiert, dass du sie direkt in WordPress einfügen kannst.


Backup und Restore von Linux-Mint in einem Dualboot-System

Voraussetzungen

  • Dualboot-PC mit Windows 10 + Linux-Mint.
  • Externe USB-HDD groß genug für die Linux-Mint-Partition(en).
  • Live-USB oder Live-DVD von Linux (z. B. Mint, Lubuntu, Xubuntu).
  • Grundkenntnisse im Terminal.

1️⃣ USB-HDD vorbereiten

  1. USB-HDD anschließen.
  2. Im Terminal prüfen, wie die Platte erkannt wird:
lsblk
  • Beispiel:
sda  500G  <--- interne Festplatte
sdb  1T    <--- externe USB-HDD
  1. Partitionieren & formatieren (optional, z. B. EXT4 für Linux-Backup):
sudo mkfs.ext4 /dev/sdb1
  1. Mountpoint erstellen:
sudo mkdir /mnt/usbbackup
sudo mount /dev/sdb1 /mnt/usbbackup

2️⃣ Linux-Mint sichern (rsync-Methode)

  1. Starte von Live-USB → verhindert, dass laufende Prozesse die Dateien sperren.
  2. Linux-Mint-Partition mounten:
sudo mkdir /mnt/linux
sudo mount /dev/sdaX /mnt/linux
  • sdaX ist deine Linux-Mint-Rootpartition.
  • Wenn du eine separate /home-Partition hast, mounten:
sudo mkdir /mnt/home
sudo mount /dev/sdaY /mnt/home
  1. Backup mit rsync:
sudo rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} /mnt/linux/ /mnt/usbbackup/linux-root/
  • Wenn /home separat ist:
sudo rsync -aAXv /mnt/home/ /mnt/usbbackup/linux-home/

✅ Vorteil: Flexibel, Backup auf Partition beliebiger Größe, kein Risiko der gesamten HDD.


3️⃣ Bootloader sichern (GRUB)

Damit du später Linux-Mint wieder booten kannst, auch in Dualboot:

  1. GRUB auf der USB-HDD sichern:
sudo grub-install --boot-directory=/mnt/usbbackup/linux-root/boot /dev/sdb
sudo update-grub

4️⃣ Linux-Mint wiederherstellen

Wenn du das Backup zurückspielen willst:

  1. Starte wieder von Live-USB.
  2. Partitionen vorbereiten:
sudo mkfs.ext4 /dev/sdaX    # Root
sudo mkfs.ext4 /dev/sdaY    # Home, falls separat
  1. Mounten:
sudo mount /dev/sdaX /mnt/linux
sudo mount /dev/sdaY /mnt/home
sudo mount /dev/sdb1 /mnt/usbbackup
  1. Restore mit rsync:
sudo rsync -aAXv /mnt/usbbackup/linux-root/ /mnt/linux/
sudo rsync -aAXv /mnt/usbbackup/linux-home/ /mnt/home/
  1. GRUB wiederherstellen:
sudo grub-install --boot-directory=/mnt/linux/boot /dev/sda
sudo update-grub

5️⃣ Hinweise

  • Datei vs. 1:1-Kopie: Mit rsync sicherst du nur Linux, Windows bleibt unberührt.
  • Vollständige 1:1-Kopie: Willst du die gesamte Festplatte klonen, kannst du dd verwenden, dann wird auch Windows gesichert.
  • Sicherheit: Immer Live-System verwenden, um aktive Partitionen nicht zu beschädigen.
  • Testen: Nach Restore unbedingt prüfen, ob GRUB die Dualboot-Auswahl korrekt anzeigt.

So hast du ein komplettes Linux-Mint-Backup, kannst neue Systeme testen und Linux-Mint später problemlos wiederherstellen, ohne Windows zu beeinträchtigen.


Wenn du willst, kann ich noch eine kompakte Version für WordPress schreiben, mit sauberen Codeblöcken und Nummerierung, damit sie direkt wie eine Anleitung im Blog aussieht. Willst du, dass ich das mache?

13. September 2025 · Kommentieren · Kategorien: Allgemein, Pico · Tags:

Ich möchte untersuchen wie genau eine Gleichspannung sein kann, die mittels PWM mit einem Pico2 erzeugt werden kann. Dazu habe ich Chatgpt.com befragt:

Natürlich 👍 – ich fasse dir unseren Chat in einen gut lesbaren Artikeltext zusammen, den du direkt in WordPress einfügen kannst (als normalen Beitrag oder Seite).


PWM und GPIO-Treiber beim Raspberry Pi Pico2 (RP2350)

Der neue Raspberry Pi Pico2 (RP2350) bietet einige interessante Features, die auch für Anwendungen mit PWM-Ausgabe und GPIO-Treibern wichtig sind. Hier findest du eine Zusammenfassung der wichtigsten Punkte aus der Praxis.


Einstellbarer Ausgangsstrom der GPIOs

Die GPIO-Pins des RP2040 und RP2350 lassen sich in ihrer Treiberstärke (Drive Strength) konfigurieren. Es gibt vier Stufen:

  • 2 mA
  • 4 mA
  • 8 mA
  • 12 mA

Zusätzlich kann die Slew-Rate (Flankensteilheit) zwischen „slow“ und „fast“ eingestellt werden.

Damit lässt sich sowohl die Belastbarkeit (z. B. LEDs oder andere Bauteile treiben) als auch das EMV-Verhalten optimieren.


Beispiel in MicroPython

Über die padsbank0-Register lässt sich die Drive-Strength direkt setzen:

import machine

# Basisadresse für padsbank0
PADS_BASE = 0x4001c000
PADS_GPIO0 = PADS_BASE + 0x04  # GPIO0, weitere Pins jeweils +4

def set_drive(pin, strength=3, fast=True):
    """
    pin       : GPIO-Nummer
    strength  : 0=2mA, 1=4mA, 2=8mA, 3=12mA
    fast      : True = schnelle Slew-Rate
    """
    addr = PADS_GPIO0 + 4*pin
    reg = machine.mem32[addr]
    reg = (reg & ~0b11) | (strength & 0b11)
    if fast:
        reg |= (1 << 2)
    else:
        reg &= ~(1 << 2)
    machine.mem32[addr] = reg

# Beispiel: GPIO15 mit 12 mA und schneller Slew-Rate
set_drive(15, strength=3, fast=True)

Auch wenn ein Pin auf PWM-Funktion gestellt wird, gilt diese Einstellung weiterhin.


Innenwiderstand der Treiber

Ein fester „Innenwiderstand“ der GPIO-Treiber ist nicht spezifiziert.

  • Die Angabe 2/4/8/12 mA beschreibt nur die Ziel-Treibefähigkeit.
  • Reale Messungen zeigen, dass kurzfristig deutlich höhere Ströme fließen können.
  • Der effektive Widerstand ergibt sich aus der Lastsituation (z. B. bei 12 mA-Einstellung etwa einige zehn Ohm).

Für definierte Verhältnisse empfiehlt sich daher ein externer Serienwiderstand.


Fractional Clock Divider

Beim PWM-Modul wird der Taktteiler (Clock Divider) als 12.4 fixed-point Wert eingestellt:

  • 12 Bit Ganzzahl
  • 4 Bit Bruchteil (in 1/16-Schritten)

Beispiel:

  • „8.4 fractional clock divider“ = 8 + 4/16 = 8.25

Damit lassen sich PWM-Frequenzen sehr fein einstellen.


Maximale PWM-Frequenz bei 16-Bit Auflösung

Die PWM-Frequenz berechnet sich zu: fPWM=fsysclkdiv×(TOP+1)f_{PWM} = \frac{f_{sys}}{\text{clkdiv} \times (TOP+1)}

  • Systemtakt Pico2: 150 MHz
  • TOP = 65535 (16 Bit)
  • clkdiv = 1.0

fPWM=150 000 00065 536≈2.3 kHzf_{PWM} = \frac{150\,000\,000}{65\,536} \approx 2.3 \,\text{kHz}

👉 Bei voller 16-Bit-Auflösung sind also nur ca. 2,3 kHz PWM-Frequenz möglich.


Frequenz vs. Auflösung (150 MHz, clkdiv=1.0)

AuflösungZählerumfangMax. FrequenzPeriode
8 Bit256585.9 kHz1.71 µs
10 Bit1024146.5 kHz6.83 µs
12 Bit409636.6 kHz27.3 µs
14 Bit163849.16 kHz109 µs
16 Bit655362.29 kHz437 µs

Je höher die Auflösung, desto niedriger die maximale PWM-Frequenz – und umgekehrt.


Fazit

  • GPIO-Treiber des RP2350 sind in 4 Stufen (2–12 mA) einstellbar, mit wählbarer Slew-Rate.
  • PWM kann mit feiner Frequenzabstufung über Fractional Divider betrieben werden.
  • Max. 16-Bit PWM: ca. 2,3 kHz bei 150 MHz Systemtakt.
  • Für höhere Frequenzen muss die Auflösung reduziert werden.

Grundsätzliche Überlegungen.

Die Erste Fragestellung entstand, weil ich bei früheren Versuchen mit einem niederohmigen RC-Glied festgestellt habe, das die minimale und maximale Spannung des Rechtecks aus dem Pin sich auf und ab bewegen. Um diesen Einfluß abschätzen zu können wäre es wichtig den Innenwiderstand der Ausgangsstufen des Pico2 zu kennen.

Die maximale Auflösung der PWM und damit der erzeugten Spannung beträgt 16-Bit. Da das Timing sehr exakt sein dürfte, könnte diese Spannung auch sehr exakt sein. Allerdings hat z.B. das oben geschilderte Phänomen sicher einen erheblichen Einfluß auf die Genauigkeit und bedarf deshalb näherer Betrachtung.

Ein weiterer Punkt ist die Konstanz der Betriebsspannung die im Pico2 erzeugt wird.

Für die Filterung des PWM-Signals zu einer Gleichspannung habe ich mich ebenfalls mit Chatgpt.com beraten. Das Ergebnis ist unter https://www.peters-bastelkiste.de/pwm-filter_001/ zu finden.

Um mein NAS-Gerät in Linux-Mint dauerhaft einzubinden habe ich mir bei Chatgpt.com Hilfe geholt.

Üblicherweise werden externe Geräte in /mnt eingebunden. Das funktioniert zwar in Linux, aber nicht in Thonny. Deshalb hat chatgpt.com vorgeschlagen das NAS in ein Verzeichnis im home-Verzeichnis zu mounten:

mkdir -p ~/nas

Anschließend ist dann in /etc/fstab folgende Zeile am Ende einzufügen:

//192.168.1.100/share /home/username/nas cifs credentials=/home/username/.qnap-cred,uid=1000,gid=1000,iocharset=utf8,nofail,x-systemd.automount 0 0

und mit

sudo mount -a

einbinden.
Das geht auch als ‚Einzeiler‘:

read -p "NAS-Benutzername: " NASUSER; read -sp "NAS-Passwort: " NASPASS; echo; sudo mkdir -p /home/username/nas &amp;&amp; echo -e "username=$NASUSER\npassword=$NASPASS" > ~/.nas-cred &amp;&amp; chmod 600 ~/.nas-cred &amp;&amp; sudo sh -c "echo '//192.168.1.100/Share /home/username/nas cifs credentials=/home/$USER/.nas-cred,uid=$(id -u),gid=$(id -g),iocharset=utf8 0 0,nofail,x-systemd.automount' >> /etc/fstab"

Ich hoffe das ich das jetzt alles korrekt dokumentiert habe.

Konzept

Hier geht es um einen Filter um aus einem PWM-Signal eine präzise Gleichspannung zu machen.

Es besteht aus drei Teilen:

  • RC-Glied
  • Puffer
  • Sellen-Key-Filter

Entwicklung

Es wurde zusammen mit Chatgpt.com entwickelt.

Berechneter Rippel (p-p)8.0 µV.

Damit ist von der Filterseite her alles getan was erforderlich ist.

Ich habe die Schaltung mit LTSpice simmuliert:

Hier das Ergebnis der Simmulation für 5kHz und 5µS Impulsdauer. Die Zoomdarstellung zeigt, dass ab ca. 120mS die Spannung sich nicht mehr verändert.

Der von Chatgpt.com angegebene Ripple vom 8µV wird durch die Simmulation bestätigt.

Praktische Erprobung

Meine Erfahrungen mit dem ESP32-C3-Board mit 0.42″ Display.

Der erste Schritt – Inbetriebnahme mit Micropython

Ein Micropythonimage zu finden war kein Problem. Unter https://micropython.org/download/ESP32_C3 kann man das herunterladen. Es ist auf die nur 4MB Flash des C3 ausgelegt. Ich habe das Image für den C3-Mini von Wemos genommen. Das hat funktioniert.

Am spannensden war die Inbetriebnahme des Displays. Die Datenlage hierzu ist sehr begrenzt. Offiziell sind nur die Pins des I2C-Busses bekannt: SCL = GPIO6, SDA = GPIO5. Zum Controller ist bei den Verkäufern in China nichts zu finden. ChatGPT.com tippte auf SSD1306.

Ich habe dann in Thonny den ssd1306-Treiber geladen und das von chatgpt vorgeschlagene Testprogrammvorschlag ausprobiert. Und … es funktionierte. Hier das von mir etwas erweiterete Testprogramm:

# Erster Displaytest -> OK

from machine import Pin, I2C
import ssd1306
import gc

# Display I2C
Disp_SCL = const(6)
Disp_SDA = const(5)

# Allgemeiner I2C
SCL = const(9)
SDA = const(8)

# Display Test
i2c = I2C(0, scl=Pin(Disp_SCL), sda=Pin(Disp_SDA))
oled = ssd1306.SSD1306_I2C(72, 40, i2c)
oled.fill(0)
oled.text("Hallo C3", 0, 0)
oled.text("OK", 0, 10)
oled.text(str(gc.mem_free()) + ' kB', 0, 30)
oled.show()

Weitere Fonts verwenden

Den ADC des C3 untersuchen

Gemäß dem Datenblatt des ESP32-C3 beträgt:

  • DNL -7 … 7 LSB – bei 3,3V -> 0.0056 V oder 0.17 %
  • INL -12 … 12 LSB – bei 3,3 V -> 0.0097 V oder 0.29 %

Soweit erstmal meine Ersten Erfahrungen. Sobald ich neue Erkenntnisse habe werde ich sie hier veröffentlichen.

Ich habe den ADC im Pico2 einmal näher untersucht. Als Board habe ich den WeAct V20 verwendet, weil bei diesem Board der Referenzspannungsanschluß heraus geführt ist.

Ich habe mit einem TL431 eine Referenzspannung von 3,1514 Volt (+- 30µV) erzeugt. Ausserdem habe ich den Spannungswandler auf PWM-Betrieb gestellt:

from machine import ADC, Pin
adc = ADC(Pin(28))
power_mode = Pin(23, Pin.OUT)
power_mode.value(1)   # PWM einschalten

Als Testspannung habe ich die Referenzspannung eines weiteren TL431 (2,5063 +-100µV) verwendet.

Die Referenzspannungen wurden aus einem externen linearen Netzteil mit 5 Volt versorgt.

Dabei konnte ich feststellen, dass es bei Einzelmessungen zu nicht unerheblichen Abweichungen kommt. Ich habe dann ein Sample aus 50.000.000 Messwerten auf ihre Abweichungen untersucht:

Hier zeigt sich, das die meisten Messungen innerhalb von 1% Abweichungen lagen, aber auch 5,2% Abweichungen bis zu 5% aufwiesen. Erfreulich ist, das keine Abweichungen > 5% aufgetreten sind.

Diese Daten beziehen sich nur auf ein Pico2 Exemplar und eine Messspannung. Weitere Tests werden folgen.

Zwischendurch möchte ich meine Raspberry Pi’s mit einer HDD verbinden. Ich habe davon noch ein paar herumliegen. Eine gute Anleitung dazu habe ich hier gefunden: https://www.youtube.com/watch?v=5S7VL8tb-fc

Weitere Links zum Thema:

Meine Verssuche das CYD mit Micropython zu betreiben.

Meine ersten Versuche waren noch nicht sehr erfolgreich. Letztendlich war es mir gelungen Das Display zum Leben zu erwecken. Allerdings wurden die Farben als BGR dargestellt, was ich nicht ändern konnte.

Schließlich konnte ich das CYD nicht mehr mit Thonny erreichen und habe Micropython neu installiert. Damit waren dann aber auch alle meine bisherigen Versuche und Änderungen gelöscht.

Nun also ein neuer Anlauf.

Zuerst erstelle ich mal eine Gliederung, das hilft mir strukturierter vorzugehen und bietet die Möglichkeit meiner Ergebnisse gleich an der richtigen Stelle zu dokumentieren – bevor ich wieder MPY neu aufspiele.

Das CYD, Daten, Eigenschaften und Varianten

Micropythonspezifische Informationen zum CYD

Hier meine aktuelle Linksammlung zum Thema:

CYD Links:

Das Display

Ich möchte zuerst das Display benutzen können. Es handelt sich dabei um einen Controller ILI9341.

Hier sind die Pinbelegungen des CYD dargestellt. Für das Display ist dort folgendes aufgeführt:

disp = ili9XXX.ili9341(factor=32, double_buffer=False, clk=14, cs=15, dc=2, rst=12, power=23, backlight=21, miso=12, mosi=13,width=320, height=240, backlight_on=1, rot=ili9XXX.LANDSCAPE)

Da dort ein anderer Treiber verwendet wird sind noch weitere Parameter enthalten, die bei dem von mir verwendeten Treiber nicht vorhanden sind.

Ich habe zuerst den ili9341.py Treiber von hier ausprobiert. Ich habe ihn nach /lib auf dem ESP32 kopiert und dann mit dem Demoprogramm demo_fonts8x8_bgcolor.py getestet.

In der Initialisierungssequenz habe ich die Zeile

self.write_cmd(self.INVON)        # Ergänzt

hinzugefügt, da ich von meinen ersten Versuchen noch wusste, das das etwas gebracht hat. Es hat sich aber gezeigt, dass die Invertierung falsch war. Siehe weiter unten.

Aber auch damit erschien kein Bild. Deshalb habe ich die Anschlüsse in demo_fonts8x8_bgcolor.py überprüft. Die waren falsch. Hier die Richtigen.

In ili9341.py ist eine falsche Geometrie als Default eingetellt. Deshalb muss hier noch width und hight angegeben werden.

spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
display = Display(spi, dc=Pin(2), cs=Pin(15), rst=Pin(12), width=320, height=240)

Auch das zeigte kein Bild. Es fiel mir aber auf, das die Hintergrundbeleuchtung des Displays nicht leuchtete. Deshalb habe ich Pin21 manuell eingeschaltet:

bl = machine.Pin(21, machine.Pin.OUT)
bl.on()

Und siehe da, das Display wurde hell und test() zeigte etwas an!

Nun habe ich die folgenden Zeilen in der REPL eingegeben:

spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
display = Display(spi, dc=Pin(2), cs=Pin(15), rst=Pin(12), width=320, height=240)
display.draw_text8x8(100, 120, "sollte Grün sein!", color565(0, 255, 0))

Der Text wurde angezeigt, aber in Lila. Außerdem enthält der Default 8×8 Font kein ü, es wird wohl der aus dem MPY Framebuffer sein.

Da Lila die Komplementärfarbe zu Grün ist war wohl die Invertierung falsch. Nachdem ich diese Zeile auskommentiert hatte wurde der Text auch Grün angezeigt.

Display ON/OFF

In der __init__ Methode von Display in ili9341.py steht in Zeile 171:

self.write_cmd(self.DISPLAY_ON)

Ich hatte angenommen, dass damit das Display eingeschaltet wird. Das passiert auch, aber die Hintergrundbeleuchtung hat damit nichts zu tun! Diese muß extra eingeschaltet werden:

bl = Pin(21, Pin.OUT)
bl.on()

Statt on/off kann man auch einen PWM-Anschluss darauf legen und so die Helligkeit einstellen.

Soweit ist also die grundsätzliche Funktion des Displays hergestellt.

CYDR.py

CYDR.py fasst die Möglichkeiten der Platine in einem Objekt zusammen. Das vereinfacht den Start gewaltig. Jetzt werde ich dieses Modul mal ausprobieren.

Ich habe die Datei cydr.py mit Thonny gestartet (entspricht einem Import). Dann das unten dargestellte Protokoll habe ich anschließend durchgeführt. Die getesteten Methoden habe alle funktioniert!

MicroPython v1.23.0 on 2024-06-02; Generic ESP32 module with ESP32

Type "help()" for more information.

>>> %Run -c $EDITOR_CONTENT

MPY: soft reboot
Booting...
>>> %Run -c $EDITOR_CONTENT

MPY: soft reboot
Booting...
>>> cyd = CYD(rgb_pmw=False, speaker_gain=512, display_width=320, display_height=240, wifi_ssid = None, wifi_password = None)
CYD ready...
>>> cyd.display.draw_text8x8(100, 120, "sollte Grün sein!", color565(0, 255, 0))
>>> cyd.touches()
(0, 0)
>>> cyd.touches()
(245, 113)
>>> cyd.touches()
(236, 279)
>>> cyd.play_tone(1000, 100, gain=0)
>>> cyd.play_tone(1000, 100, gain=0)
>>> cyd.wifi_connect('ssid', 'password')
connecting to network...
network config: 192.168.3.180
>>> 
  • cyd = CYD(rgb_pmw=False, speaker_gain=512, display_width=240, display_height=320, wifi_ssid = None, wifi_password = None)
    • Initialize CYD class
    • OK
  • cyd.display.ili9341_cydr_function_name()
    • Use to access ili9341_cydr functions.
    • OK
  • cyd._touch_handler(x, y)
    • Called when a touch occurs.
    • INTERNAL USE ONLY
  • cyd.touches()
    • GETS the last touch coordinates.
    • OK
  • cyd.double_tap(x, y, error_margin = 5)
    • Check for double taps.
    • ?
  • cyd.rgb(color)
    • SETS rgb LED color.
    • OK
  • cyd._remap(value, in_min, in_max, out_min, out_max)
    • Converts a value form one scale to another.
    • INTERNAL USE ONLY
  • cyd.light()
    • GETS the current light sensor value.
    • liefert nur 0.0 zurück.
  • cyd.button_boot()
    • GETS the current boot button value.
    • gibt <bound_method> zurück.
  • cyd.backlight(value)
    • SETS backlight brightness.
    • Es geht nur 1 und 0.
  • cyd.play_tone(freq, duration, gain=0)
    • Plays a tone for a given duration.
    • OK
  • cyd.mount_sd()
    • Mounts SD card
    • OK
  • cyd.unmount_sd()
    • Unmounts SD card.
    • Failed to unmount SD card
      • Laufwerk sd lässt sich nicht unmounten.
  • cyd.wifi_connect(ssid, password)
    • Connects to a WLAN network.
    • OK
  • cyd.wifi_isconnected()
    • Checks to see that the wifi connection is connected.
    • OK
  • cyd.wifi_ip()
    • Get the CYD’s IPv4 address on your WLAN.
    • OK
  • cyd.wifi_create_ap(_ssid)
    • Creates an Access Point (AP) WLAN network.
    • ?
  • cyd.shutdown()
    • Safely shutdown CYD device
      • Failed to unmount SD card
      • display off
      • ========== Goodbye ==========
      • Micropython steht in der REPL weiterhin zur Verfügung.

TODO

  • Backlight ein- und ausschalten in backlight_on() und backlight_off() integrieren.

Ich probiere gerade mit der UIFlow-IDE ein kleines Programm zu erstellen, das mittels ESP-Now eine Verbindung herstellt und Daten austauscht.

Mein erster Versuch (Master):

  • Zuerst wird ESP-Now initialisiert.
  • Dann wird ein Name (SSID) für die Arbeitsgruppe festgelegt.
  • Und schließlich die eigene MAC-Adresse geholt und angezeigt.
  • In der folgenden Schleife wird nach einem Mitglied der Arbeitsgruppe gesucht und dessen MAC angezeigt.
  • Das Mitglied wird dann in eine Liste eingetragen.
  • Die MainLoop ist noch nicht getestet.

Das Programm auf dem Slave:

  • Auch hier wird zuerst ESP-Now initialisiert.
  • Dann wird der Arbeitsgruppennamen (SSID) festgelegt und bekanntgemacht.
  • Schließlich wird die eigene MAC-Adresse geholt und angezeigt.

Mehr macht dieses Programm nicht. Das genügt aber, um vom Master erkannt zu werden!

Eine zuverlässige Datenübertragung hat aber nicht funktioniert.

Ein zweiter Anlauf

Also das Beispiel von MStack hat nicht funktioniert. Ich habe heute einen neuen Anlauf gemacht. Es funktionierte wieder nichts. Also habe ich einen ESP32 genommen und die Micropython Demo als Grundlage genommen. Das funktionierte in Thonny:

# ESPNow_test_001.py
#


import network
import espnow

sta = network.WLAN(network.STA_IF)  # Or network.AP_IF
sta.active(True)

e = espnow.ESPNow()
e.active(True)

peer = b'\x94\xb9\x7e\x8d\x41\xdc'
e.add_peer(peer)

Dieses kleine Programm hat einen ESP-Now Sender erzeugt. Mit

>>> e.send(peer, "Starting...")
True

habe ich senden können. Das Programm RX_001.m5f hat diese Aussendungen empfangen. Es waren noch kleine Fehler drinn, deshalb hier die endgültige Fassung:

Wenn eine Message empfangen wird, so wird die MAC des Senders und die Nachricht für 1 Sekunde angezeigt, dann erscheinen wieder —.

Dann habe ich am Senderprogramm gearbeitet. Das automatische Suchen von Peers habe ich rausgeschmissen und die MAC des Peers (Empfänger) ins Programm geschrieben. Damit funktionierte dann auch der Sender. Hier das Programm TX_003.m5f:

Damit ist die Grundlage für eine einseitige Verbindung mittels ESP-Now geschaffen.

Das automatische finden des Peer hat prinzipiell funktioniert. Allerdings wurde eine Slave-MAC angezeigt, die um 1 höher war, als die vom Slave selbst angezeigte.

Nachgedanken

Es ist möglich, dass der Erste Versuch unbefriedigend verlief, weil ich den Kanal auf 0 eingestellt hatte. Kanal 0 bedeutet, das der eingestellte Kanal verwendet wird. Wenn sich aus irgendwelchen Gründen bei Sender und Empfänger unterschiedliche Kanäle einstellen finden sie sich nicht.

Das werde ich vielleicht später mal testen. Für eine vorgesehenen Reichweitentest ist das jetzt ausreichend.

Kürzlich bin ich auf ein Projekt gestoßen, das mittels Adafruit_TinyUSB-Library mit einem Raspberry Pi Pico Tastatureingaben simuliert hat. Hier werde ich mir die Technik dafür erarbeiten. Deshalb befindet sich diese Seite z.Z. noch im Entstehungsmodus.

Die Entwicklungsbasis ist das Pico Restouch LCD 3,5″ Display von Waveshare. Bestückt mit einen Pico, der im Lieferumfang von azdelivery.de enthalten war. Außerdem gibt dazu einen Projektvorschlag für einen Tastatursimulator. Als IDE kommt die Arduino-IDE zum Einsatz.

Die Adafruit_TinyUSB Library stellt verschiedene HID’s (Human Interface Device) zur Verfügung. Mich interessiert hier nur die Keyboard HID. Ein Beispiel für deren Anwendung befindet sich hier. Ich habe aus diesem Beispiel nur die Teile heraus gesucht, die für das Keyboard-HID erforderlich sind:

Zuerst muss die Headerdatei eingebunden werden.

#include "Adafruit_TinyUSB.h"

Dann wird das Keyboard eingerichtet:

// -------- USB HID KEYBOARD -----------
enum { RID_KEYBOARD = 1 };
uint8_t const desc_hid_report[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)) };
uint8_t keycode[6] = { HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE };
Adafruit_USBD_HID usb_hid;

keycode[] ist ein Array in dem der zu übertragende Text aufbereitet und an usb_hid übergeben wird. Dafür stehen Konstanten in hid.h zur Verfügung.

Ob keycode[] nur 6 Elemente enthalten darf werde ich später noch klären.

Die Anwendung ist dann ganz einfach:

keycode[0] = HID_KEY_C;
usb_hid.keyboardReport(RID_KEYBOARD, KEYBOARD_MODIFIER_LEFTCTRL, keycode);
delay(10);
usb_hid.keyboardRelease(RID_KEYBOARD);
  • In keycode[] werden die Werte eingetragen.
  • Der KEYBOARD_MODIFIER ist normalerweise 0.
  • Mit usb_hid.keyboardReport() werden die Daten zum PC geschickt.
  • Dann wird kurz gewartet (wahrscheinlich hier 10mS).
  • Und schließlich mit usb_hid.keyboardRelease() dem PC mitgeteilt, dass die Übertragung beendet ist.

Die Übertragung ist sehr zeitkritisch! Zwei gleiche Zeichen direkt hintereinander (Hallo) funktioniert meistens nicht. Hier das Ergebnis zur zuverlässigen Übertragung von „Hallo\n“:

// ----- btn_12 action
void btn_12_pressAction(void) {
  if (btn_12.justPressed()) {
    keycode[0] = HID_KEY_H;
    keycode[1] = HID_KEY_NONE;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, KEYBOARD_MODIFIER_LEFTSHIFT, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_A;
    keycode[1] = HID_KEY_L;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_L;
    keycode[1] = HID_KEY_O;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_ENTER;
    keycode[1] = HID_KEY_ENTER;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    btn_12.drawSmoothButton(true);
  }
}
void btn_12_releaseAction(void) {
  if (btn_12.justReleased()) {
    usb_hid.keyboardRelease(RID_KEYBOARD);
    btn_12.drawSmoothButton(false);
  }
}

Sonderbarer Weise wird Enter nur zuverlässig übergeben, wenn es zweimal gesendet wird! Es kommt zu keiner doppelten Erkennung! Es funktioniert auch, wenn Enter im ersten und im letzten Element übergeben werden.

Mysterium

Wenn schon vorher Text eingegeben wurde wird meistens 2x \n ausgegeben?!