Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Pico-Powered Boot Switch: OS vor dem Einschalten per Schalter wählen

OS vor dem Einschalten per Schalter vorwählen – kein Warten auf GRUB-Menü mehr beim Dual-Boot.

Story

Auf Hackaday.io stieß ich auf dieses Projekt (Link) von Stephen Holdaway. Er löste eine frustrierende Aufgabe jedes Dual-Boot-Nutzers: Sitzen und Warten auf GRUB-Menü, um OS (Windows) auszuwählen beim Wechsel. Er fügte einen Hardware-Schalter hinzu, der bei jedem Einschalten das zu bootende OS bestimmt.

Er erreichte dies, indem er STM32 Mikrocontroller als USB Mass-Storage-Device konfigurierte. Seine gesamte Reise von Forschung bis Implementierung dokumentierte er im Hackaday Post (Link). Bitte durchlesen für tieferes Verständnis.

In diesem Projekt zeige ich, wie ich die Änderungen auf Raspberry Pi Pico portierte. Meine Version finden Sie in diesem GitHub Repo (Link).

Konzept

GNU GRUB läuft vor Laden jeglicher Operating Systems. Über dieses Menü wählen wir das zu ladende OS. GRUB bietet sehr limitierte Module – es kann keine Daten von Mikrocontroller via USB lesen. Aber es kann Daten von Storage-Disks lesen.

Also tricksen wir GRUB, indem wir unseren Mikrocontroller als Mass-Storage-Device enumerieren.

Daher enumerieren wir Raspberry Pi Pico als Mass-Storage-Device via tinyUSB Library, das eine Datei switch.cfg enthält, in die Pico die Schalterposition schreibt: 1 für ON, 0 für OFF.

Wir müssen ein Skript in GRUB hinzufügen, das switch.cfg liest und default auf 0 (Ubuntu) / 2 (Windows) setzt.

GRUB lädt, führt unser Custom-Skript aus, das nach unserem Device via UUID sucht, und falls existent switch.cfg liest. Nach Erhalt der Schalterposition setzt es die Default-OS-Selektion entsprechend.

Zusammenfassend:

Pico als Mass-Storage-Device konfigurieren

Ich nutzte cdc_msc Example von tinyUSB. Das Example konfiguriert Pico als Mass-Storage-Device, erstellt FAT12 Filesystem und enumeriert README.txt Datei.

Ich änderte README.txt zu switch.cfg und fügte Zeile „set os_hw_switch=0\n“ zur Datei hinzu.

#define SWITCH_CFG_CONTENTS \
"set os_hw_switch=0\n"

...
//------------- Block3: Readme Content -------------//
SWITCH_CFG_CONTENTS

Pico ist nun als Mass-Storage-Device konfiguriert. Nach Kopieren der UF2-Datei auf Pico enumeriert es als Storage-Device. Wir brauchen UUID des Devices für GRUB-Skript: UUID="0000-1234".

$ sudo blkid
...
/dev/sda: SEC_TYPE="msdos" LABEL_FATBOOT="TinyUSB MSC" LABEL="TinyUSB MSC" UUID="0000-1234" BLOCK_SIZE="512" TYPE="vfat"

Schaltung

Schalterposition lesen und in Datei schreiben

Jetzt Schalterposition lesen und Inhalt von switch.cfg entsprechend ändern:

GPIO_PIN 28 als Schalter-Pin genutzt, auf Pull-Down konfiguriert.

read_switch_value gibt Schalterposition zurück: '1' = on (pulled high), '0' = off (pulled low).

//-------------------------main.c---------------------
#define SWITCH_PIN 28

// read switch value
uint8_t read_switch_value()
{
    return gpio_get(SWITCH_PIN) ? '1' : '0';
}

int main(void)
{
    gpio_init(SWITCH_PIN);
    // Pin als INPUT konfigurieren
    gpio_set_dir(SWITCH_PIN, false);
    // Pin als PULL_DOWN konfigurieren
    gpio_set_pulls(SWITCH_PIN, false, true);

Zum Schreiben der Schalterposition in switch.cfg nutzte ich readGRUBConfig(), das read_switch_value aufruft und Output-Buffer mit Schalterposition setzt.

Ich fand heraus, dass beim Lesen des dritten Blocks lba auf 3 gesetzt ist, daher Call abfangen und readGrubConfig aufrufen mit Buffer, wohin Dateiinhalt kopiert wird.

//-------------------------msc_disk.c---------------------
static char grubConfigStr[] = "set os_hw_switch=0\n";
static void readGrubConfig(uint8_t* output)
{
    // Config String mit aktuellem Schalterwert modifizieren
    grubConfigStr[sizeof(grubConfigStr)-3] = read_switch_value();
    memcpy(output, &grubConfigStr, sizeof(grubConfigStr));
}

// Callback bei READ10 Command.
// Disk-Daten in Buffer kopieren (bis bufsize) und kopierte Bytes zurückgeben.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
    (void) lun;
    // beim Lesen der Datei
    if(lba == 3){
        readGrubConfig(buffer);
        return bufsize;
    }
    ...
    ...
}

Pico Code kompilieren

Pico stdlib zum Code hinzufügen für gpio Pin-Zugriff.

//-------------------------main.c-----------------------------------
#include 
#include 
#include 
#include "bsp/board.h"
#include "tusb.h"
...
#include "pico/stdlib.h"

Projekt bauen:

$ mkdir build
$ cd build
$ cmake ..
$ make

GRUB konfigurieren zum Lesen des Dateiinhalts

Änderungen in Ubuntu 20.10 hinzugefügt.

$ sudo vim /etc/grub.d/40_custom

....
# Hardware-Switch-Device via hardcoded Filesystem-ID suchen
search --no-floppy --fs-uuid --set hdswitch 0000-1234

# Falls gefunden, dynamische Config-Datei lesen und passenden Eintrag für jede Position wählen
if [ "${hdswitch}" ] ; then
    source ($hdswitch)/switch.cfg

    if [ "${os_hw_switch}" == 0 ] ; then
        # Boot Linux
        set default="0"
    elif [ "${os_hw_switch}" == 1 ] ; then
        # Boot Windows
        set default="2"
    else
        # Fallback zu Default
        set default="${GRUB_DEFAULT}"
    fi
else
    set default="${GRUB_DEFAULT}"
fi

Zuerst suchen wir unser Filesystem. GRUB hat Subcommand search dafür.

Falls Device gefunden, erstes gefundenes Device als Wert der Environment-Variable gesetzt.

–set hdswitch hdswitch ist unsere Environment-Variable und wird mit Disk-Name gesetzt falls gefunden.

Als Nächstes switch.cfg sourcen falls hdswitch Variable gesetzt, was weitere Environment-Variable os_hw_switch mit Schalterposition (0/1) erstellt.

Wert von os_hw_switch lesen und Default auf 0 oder 2 setzen. 0 weil Ubuntu an 0. Position, Windows an 2. Position im GRUB-Menü.

Zuletzt, falls hdswitch nicht gesetzt, Default auf GRUB_DEFAULT.

GRUB aktualisieren:

$ sudo update-grub

Quelle: Hardware Boot Select Switch Using Pico

Herstellungsprozess

  1. C# Switch Statement meistern: Syntax, Beispiele & Best Practices
  2. C# using-Anweisungen meistern: Importe, Aliase und statische Direktiven
  3. Outdoor-Wetterstation mit Raspberry Pi 2 & ADS-WS1 bauen
  4. LM35-basiertes Temperatursteuerungssystem mit AT89S52 Mikrocontroller
  5. Remote-Wetterüberwachung mit Raspberry Pi 3 & PubNub
  6. TI SensorTag mit Blynk via Node-RED auf Raspberry Pi Zero integrieren
  7. LED mit PIR-Bewegungsmelder am Raspberry Pi steuern
  8. Intelligenten Roboter mit Bridge Shield bauen – Raspberry Pi & Arduino Integration
  9. WLAN-gesteuerter Raspberry Pi Roboter mit Python bauen – Schritt-für-Schritt
  10. Embedded Hardware Hacking für IoT-Geräte: Tools, Techniken und Business-Implikationen