Dieser Artikel ist in Vorbereitung. Kommt bald.

Teil der Serie über mein privates BeagleBone-Black-Projekt.

1. Ziel

Dieses Tutorial beschreibt den Aufbau einer Yocto-Entwicklungsumgebung für den BeagleBone Black. Die komplette Build-Umgebung wird reproduzierbar in einem Ubuntu Docker Container erstellt.

Ziel:

  • Ubuntu Docker Build-Umgebung

  • Yocto Project Setup

  • BeagleBone Black BSP Integration

  • Erstes Yocto Image bauen

  • SD-Karte vorbereiten und booten

2. Voraussetzungen

Benötigt:

  • Linux Host (empfohlen Ubuntu 22.04/24.04)

  • Docker installiert

  • mindestens 50 GB freier Speicher

  • mindestens 8 GB RAM empfohlen

  • BeagleBone Black

  • SD-Karte

3. Step 1: Ubuntu Docker Build Environment erstellen

3.1. Verzeichnis anlegen

mkdir yocto-bbb
cd yocto-bbb

3.2. Dockerfile erstellen

Datei Dockerfile:

FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt update && apt install -y \
    git \
    wget \
    curl \
    vim \
    nano \
    sudo \
    locales \
    build-essential \
    gcc \
    g++ \
    make \
    chrpath \
    cpio \
    diffstat \
    gawk \
    texinfo \
    unzip \
    socat \
    python3 \
    python3-pip \
    python3-pexpect \
    xz-utils \
    file \
    iputils-ping \
    rsync \
    zstd \
    lz4 \
    bzip2 \
    && rm -rf /var/lib/apt/lists/*

RUN locale-gen en_US.UTF-8

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

RUN useradd -ms /bin/bash yocto && \
    echo "yocto ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER yocto

WORKDIR /home/yocto

CMD ["/bin/bash"]

3.3. Docker Image bauen

docker build -t yocto-bbb .

3.4. Container starten

Den aktuellen Ordner als Workspace mounten:

docker run -it \
    --name yocto-bbb-build \
    -v $(pwd):/home/yocto/workspace \
    yocto-bbb

4. Step 2: Yocto Quellen holen

Im Container:

cd ~/workspace

git clone https://git.yoctoproject.org/poky
cd poky
git checkout kirkstone
cd ..

5. Step 3: Zusätzliche Layers installieren

git clone https://git.openembedded.org/meta-openembedded

cd meta-openembedded
git fetch --all
git checkout kirkstone
cd ..

git clone https://github.com/beagleboard/meta-beagleboard.git

6. Step 4: Build Environment initialisieren

cd ~/workspace/poky
source oe-init-build-env build-bbb

7. Step 5: BeagleBone Black konfigurieren

Datei conf/local.conf bearbeiten und folgenden Eintrag setzen:

MACHINE = "beaglebone-yocto"

8. Step 6: Layers aktivieren

bitbake-layers add-layer \
    ../meta-openembedded/meta-oe

bitbake-layers add-layer \
    ../meta-openembedded/meta-python

bitbake-layers add-layer \
    ../meta-openembedded/meta-networking

bitbake-layers add-layer \
    ../meta-beagleboard

9. Step 7: Erstes Image bauen

bitbake core-image-minimal

10. Step 8: Build Ergebnis

Nach erfolgreichem Build befinden sich die Artefakte in:

tmp/deploy/images/beaglebone-yocto/

Enthält:

  • Kernel (zImage)

  • Device Tree (*.dtb)

  • U-Boot (u-boot.img, MLO)

  • Root Filesystem (core-image-minimal-beaglebone-yocto.tar.xz)

11. Step 9: SD-Karte vorbereiten

Partitionen:

boot   FAT32
rootfs ext4

Boot-Dateien kopieren:

cp MLO /boot/
cp u-boot.img /boot/
cp *.dtb /boot/
cp zImage /boot/

RootFS installieren:

tar xf core-image-minimal*.tar.xz -C /mnt/rootfs

12. Step 10: BeagleBone Black starten

UART-Verbindung herstellen:

115200 baud
8N1

Bootmeldungen beobachten und System testen.

13. GitHub Actions Workflow

Der Yocto-Build lässt sich auch automatisiert in GitHub Actions ausführen — der folgende Workflow startet einen ubuntu:22.04-Container direkt auf dem GHA-Runner, installiert alle Abhängigkeiten und baut core-image-minimal.

Ein sstate-cache- und downloads-Cache reduziert Folgebuilds von mehreren Stunden auf ca. 20–40 Minuten.

Standard-GHA-Runner haben nur ~14 GB Disk — für einen vollständigen Yocto-Build wird ein self-hosted Runner mit ≥ 50 GB Disk und ≥ 8 GB RAM empfohlen.

name: Yocto Build – BeagleBone Black

on:
  workflow_dispatch:
  push:
    paths:
      - '.github/workflows/yocto-build.yml'

jobs:
  build:
    runs-on: ubuntu-latest

    container:
      image: ubuntu:22.04
      options: --user root

    env:
      DEBIAN_FRONTEND: noninteractive
      LANG: en_US.UTF-8
      LC_ALL: en_US.UTF-8

    steps:
      - name: Install Yocto dependencies
        run: |
          apt-get update && apt-get install -y \
            git wget curl sudo locales \
            build-essential gcc g++ make \
            chrpath cpio diffstat gawk texinfo \
            unzip socat python3 python3-pip python3-pexpect \
            xz-utils file rsync zstd lz4 bzip2 \
            && locale-gen en_US.UTF-8 \
            && rm -rf /var/lib/apt/lists/*

      - name: Create yocto user
        run: |
          useradd -ms /bin/bash yocto
          echo "yocto ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

      - name: Restore sstate-cache and downloads
        uses: actions/cache@v4
        with:
          path: |
            /home/yocto/downloads
            /home/yocto/sstate-cache
          key: yocto-kirkstone-bbb-${{ hashFiles('.github/workflows/yocto-build.yml') }}
          restore-keys: |
            yocto-kirkstone-bbb-

      - name: Clone poky (kirkstone)
        run: |
          su - yocto -c "git clone --depth=1 -b kirkstone https://git.yoctoproject.org/poky /home/yocto/poky"

      - name: Clone meta-openembedded (kirkstone)
        run: |
          su - yocto -c "git clone --depth=1 -b kirkstone https://git.openembedded.org/meta-openembedded /home/yocto/meta-openembedded"

      - name: Clone meta-beagleboard
        run: |
          su - yocto -c "git clone --depth=1 https://github.com/beagleboard/meta-beagleboard.git /home/yocto/meta-beagleboard"

      - name: Initialize build environment and configure
        run: |
          su - yocto -c "
            cd /home/yocto/poky
            source oe-init-build-env /home/yocto/build-bbb
            echo 'MACHINE = \"beaglebone-yocto\"' >> conf/local.conf
            echo 'DL_DIR = \"/home/yocto/downloads\"' >> conf/local.conf
            echo 'SSTATE_DIR = \"/home/yocto/sstate-cache\"' >> conf/local.conf
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-oe
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-python
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-networking
            bitbake-layers add-layer /home/yocto/meta-beagleboard
          "

      - name: Build core-image-minimal
        run: |
          su - yocto -c "
            cd /home/yocto/poky
            source oe-init-build-env /home/yocto/build-bbb
            bitbake core-image-minimal
          "

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: beaglebone-yocto-image
          path: /home/yocto/build-bbb/tmp/deploy/images/beaglebone-yocto/
          retention-days: 7

13.1. Erweiterung: eigenes Layer und Recipes im Workflow mitbauen

Die im Abschnitt „Weiterführende Themen“ vorgestellten Erweiterungen — eigenes Layer, eigene Recipes, Kernel-/Device-Tree-Anpassung, systemd-Service und Ethernet-Konfiguration — lassen sich genauso automatisiert bauen wie core-image-minimal selbst. Das lohnt sich sobald diese Bestandteile lokal funktionieren: eine kaputte Recipe oder ein fehlerhafter Device-Tree-Patch fällt dann sofort im CI auf, statt erst beim nächsten lokalen Build.

Der erweiterte Workflow baut auf dem Basis-Workflow oben auf und fügt vier zusätzliche Schritte zwischen dem Klonen der Layer und der finalen Konfiguration ein: Anlegen von meta-mybbb, Ausrollen der hello-Recipe, des Kernel-`.bbappend`s mit Device-Tree-Anpassung sowie der systemd-Service- und Ethernet-Recipes. Die Dateien werden dabei direkt im Runner per Heredoc geschrieben — für ein reales Projekt liegen sie stattdessen versioniert im eigenen Layer-Repository, das der Workflow nur noch klont.

Die PRU-Firmware-Recipe aus dem Abschnitt „PRU-Entwicklung“ ist hier bewusst ausgeklammert: meta-ti und der ti-cgt-pru-Compiler benötigen eine manuelle TI-EULA-Bestätigung und lassen sich nicht ohne Weiteres unbeaufsichtigt in einem CI-Runner beziehen.

name: Yocto Build (erweitert) – BeagleBone Black

on:
  workflow_dispatch:
  push:
    paths:
      - '.github/workflows/yocto-build-extended.yml'

jobs:
  build:
    runs-on: ubuntu-latest

    container:
      image: ubuntu:22.04
      options: --user root

    env:
      DEBIAN_FRONTEND: noninteractive
      LANG: en_US.UTF-8
      LC_ALL: en_US.UTF-8

    steps:
      - name: Install Yocto dependencies
        run: |
          apt-get update && apt-get install -y \
            git wget curl sudo locales \
            build-essential gcc g++ make \
            chrpath cpio diffstat gawk texinfo \
            unzip socat python3 python3-pip python3-pexpect \
            xz-utils file rsync zstd lz4 bzip2 \
            && locale-gen en_US.UTF-8 \
            && rm -rf /var/lib/apt/lists/*

      - name: Create yocto user
        run: |
          useradd -ms /bin/bash yocto
          echo "yocto ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

      - name: Restore sstate-cache and downloads
        uses: actions/cache@v4
        with:
          path: |
            /home/yocto/downloads
            /home/yocto/sstate-cache
          key: yocto-kirkstone-bbb-extended-${{ hashFiles('.github/workflows/yocto-build-extended.yml') }}
          restore-keys: |
            yocto-kirkstone-bbb-extended-

      - name: Clone poky (kirkstone)
        run: |
          su - yocto -c "git clone --depth=1 -b kirkstone https://git.yoctoproject.org/poky /home/yocto/poky"

      - name: Clone meta-openembedded (kirkstone)
        run: |
          su - yocto -c "git clone --depth=1 -b kirkstone https://git.openembedded.org/meta-openembedded /home/yocto/meta-openembedded"

      - name: Clone meta-beagleboard
        run: |
          su - yocto -c "git clone --depth=1 https://github.com/beagleboard/meta-beagleboard.git /home/yocto/meta-beagleboard"

      - name: Create custom layer (meta-mybbb)
        run: |
          su - yocto <<'YOCTO_SCRIPT'
          set -e
          cd /home/yocto/poky
          source oe-init-build-env /home/yocto/build-bbb
          bitbake-layers create-layer /home/yocto/meta-mybbb
          YOCTO_SCRIPT

      - name: Add hello recipe
        run: |
          su - yocto <<'YOCTO_SCRIPT'
          set -e
          mkdir -p /home/yocto/meta-mybbb/recipes-mybbb/hello/files
          cat > /home/yocto/meta-mybbb/recipes-mybbb/hello/files/hello.c <<'HELLO_C'
          #include <stdio.h>
          int main(void) { printf("Hello from meta-mybbb\n"); return 0; }
          HELLO_C
          cat > /home/yocto/meta-mybbb/recipes-mybbb/hello/hello_1.0.bb <<'HELLO_BB'
          DESCRIPTION = "Minimal hello world example"
          LICENSE = "MIT"
          LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
          SRC_URI = "file://hello.c"
          S = "${WORKDIR}"
          do_compile() {
              ${CC} ${CFLAGS} ${LDFLAGS} hello.c -o hello
          }
          do_install() {
              install -d ${D}${bindir}
              install -m 0755 hello ${D}${bindir}
          }
          HELLO_BB
          YOCTO_SCRIPT

      - name: Add kernel config and device-tree bbappend
        run: |
          su - yocto <<'YOCTO_SCRIPT'
          set -e
          mkdir -p /home/yocto/meta-mybbb/recipes-kernel/linux/files
          cat > /home/yocto/meta-mybbb/recipes-kernel/linux/files/mybbb.cfg <<'KERNEL_CFG'
          CONFIG_LOCALVERSION="-mybbb"
          KERNEL_CFG
          cat > /home/yocto/meta-mybbb/recipes-kernel/linux/files/am335x-boneblack-mybbb.dts <<'BBB_DTS'
          /dts-v1/;

          #include "am335x-boneblack.dts"

          &am33xx_pinmux {
              uart4_pins: pinmux_uart4_pins {
                  pinctrl-single,pins = <
                      AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE6)
                      AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT_PULLDOWN, MUX_MODE6)
                  >;
              };
          };

          &uart4 {
              status = "okay";
              pinctrl-names = "default";
              pinctrl-0 = <&uart4_pins>;
          };
          BBB_DTS
          cat > /home/yocto/meta-mybbb/recipes-kernel/linux/linux-yocto_%.bbappend <<'KERNEL_BBAPPEND'
          FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
          SRC_URI:append = " file://mybbb.cfg file://am335x-boneblack-mybbb.dts"

          do_configure:append() {
              cp ${WORKDIR}/am335x-boneblack-mybbb.dts ${S}/arch/arm/boot/dts/
          }

          KERNEL_DEVICETREE:append = " am335x-boneblack-mybbb.dtb"
          KERNEL_BBAPPEND
          YOCTO_SCRIPT

      - name: Add systemd service recipe (mydaemon)
        run: |
          su - yocto <<'YOCTO_SCRIPT'
          set -e
          mkdir -p /home/yocto/meta-mybbb/recipes-mybbb/mydaemon/files
          cat > /home/yocto/meta-mybbb/recipes-mybbb/mydaemon/files/mydaemon.service <<'MYDAEMON_SERVICE'
          [Unit]
          Description=My Daemon

          [Service]
          ExecStart=/usr/bin/mydaemon

          [Install]
          WantedBy=multi-user.target
          MYDAEMON_SERVICE
          cat > /home/yocto/meta-mybbb/recipes-mybbb/mydaemon/mydaemon_1.0.bb <<'MYDAEMON_BB'
          DESCRIPTION = "Example systemd service"
          LICENSE = "MIT"
          LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

          inherit systemd

          SRC_URI = "file://mydaemon.service"
          S = "${WORKDIR}"

          SYSTEMD_SERVICE:${PN} = "mydaemon.service"
          SYSTEMD_AUTO_ENABLE = "enable"

          do_install() {
              install -d ${D}${systemd_system_unitdir}
              install -m 0644 ${WORKDIR}/mydaemon.service ${D}${systemd_system_unitdir}
          }

          FILES:${PN} += "${systemd_system_unitdir}/mydaemon.service"
          MYDAEMON_BB
          YOCTO_SCRIPT

      - name: Add Ethernet (systemd-networkd) recipe
        run: |
          su - yocto <<'YOCTO_SCRIPT'
          set -e
          mkdir -p /home/yocto/meta-mybbb/recipes-mybbb/network-config/files
          cat > /home/yocto/meta-mybbb/recipes-mybbb/network-config/files/10-eth0.network <<'ETH0_NETWORK'
          [Match]
          Name=eth0

          [Network]
          Address=192.168.7.2/24
          Gateway=192.168.7.1
          DNS=192.168.7.1
          ETH0_NETWORK
          cat > /home/yocto/meta-mybbb/recipes-mybbb/network-config/network-config_1.0.bb <<'ETH0_BB'
          DESCRIPTION = "Static Ethernet configuration for eth0"
          LICENSE = "MIT"
          LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

          SRC_URI = "file://10-eth0.network"
          S = "${WORKDIR}"

          do_install() {
              install -d ${D}${sysconfdir}/systemd/network
              install -m 0644 ${WORKDIR}/10-eth0.network ${D}${sysconfdir}/systemd/network
          }

          FILES:${PN} += "${sysconfdir}/systemd/network/10-eth0.network"
          ETH0_BB
          YOCTO_SCRIPT

      - name: Initialize build environment and configure
        run: |
          su - yocto -c "
            cd /home/yocto/poky
            source oe-init-build-env /home/yocto/build-bbb
            echo 'MACHINE = \"beaglebone-yocto\"' >> conf/local.conf
            echo 'DL_DIR = \"/home/yocto/downloads\"' >> conf/local.conf
            echo 'SSTATE_DIR = \"/home/yocto/sstate-cache\"' >> conf/local.conf
            echo 'DISTRO_FEATURES:append = \" systemd\"' >> conf/local.conf
            echo 'VIRTUAL-RUNTIME_init_manager = \"systemd\"' >> conf/local.conf
            echo 'VIRTUAL-RUNTIME_initscripts = \"\"' >> conf/local.conf
            echo 'IMAGE_INSTALL:append = \" hello mydaemon network-config\"' >> conf/local.conf
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-oe
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-python
            bitbake-layers add-layer /home/yocto/meta-openembedded/meta-networking
            bitbake-layers add-layer /home/yocto/meta-beagleboard
            bitbake-layers add-layer /home/yocto/meta-mybbb
          "

      - name: Build core-image-minimal
        run: |
          su - yocto -c "
            cd /home/yocto/poky
            source oe-init-build-env /home/yocto/build-bbb
            bitbake core-image-minimal
          "

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: beaglebone-yocto-image-extended
          path: /home/yocto/build-bbb/tmp/deploy/images/beaglebone-yocto/
          retention-days: 7

14. Weiterführende Themen

Mit dem Grundgerüst aus den vorherigen Schritten lässt sich ein funktionierendes Image bauen — für den produktiven Einsatz kommt man aber schnell an den Punkt, an dem eigene Layer, eigene Recipes und Anpassungen an Kernel und Device Tree nötig werden. Die folgenden Abschnitte geben dazu jeweils einen kompakten Einstieg.

14.1. Eigenes Yocto Layer erstellen

Eigener Code — Recipes, .bbappend-Dateien, Konfiguration — gehört nicht in meta-beagleboard oder poky, sondern in ein eigenes Layer. Das hält Änderungen von Upstream-Layern getrennt und macht sie versionierbar.

cd ~/workspace/poky
bitbake-layers create-layer ../meta-mybbb
bitbake-layers add-layer ../meta-mybbb

Das erzeugt folgende Struktur:

meta-mybbb/
├── conf/
│   └── layer.conf
├── COPYING.MIT
├── README
└── recipes-example/
    └── example/
        └── example_0.1.bb

Ob das Layer korrekt eingebunden ist, zeigt:

bitbake-layers show-layers

14.2. Eigene Recipes schreiben

Eine Recipe beschreibt, wie eine Software geholt, gebaut und installiert wird. Als Minimalbeispiel ein selbst geschriebenes „Hello World“-Programm im eigenen Layer:

meta-mybbb/recipes-mybbb/hello/hello_1.0.bb
meta-mybbb/recipes-mybbb/hello/files/hello.c
# hello_1.0.bb
DESCRIPTION = "Minimal hello world example"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

SRC_URI = "file://hello.c"
S = "${WORKDIR}"

do_compile() {
    ${CC} ${CFLAGS} ${LDFLAGS} hello.c -o hello
}

do_install() {
    install -d ${D}${bindir}
    install -m 0755 hello ${D}${bindir}
}

Damit die Recipe im Image landet, in conf/local.conf oder einem .bbappend für core-image-minimal:

IMAGE_INSTALL:append = " hello"

Bauen und prüfen:

bitbake hello
bitbake core-image-minimal

14.3. Kernel-Änderungen und Device Tree Anpassungen

Kernel-Konfiguration lässt sich interaktiv über menuconfig anpassen:

bitbake -c menuconfig virtual/kernel

Die Änderungen werden als Config-Fragment gesichert und in ein .bbappend übernommen:

meta-mybbb/recipes-kernel/linux/linux-yocto_%.bbappend
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://mybbb.cfg"

14.3.1. Device Tree anpassen

Das beaglebone-yocto-Machine-Target baut den Device Tree statisch aus den Quellen im Kernel mit — anders als beim offiziellen BeagleBone-Debian-Image gibt es hier keinen Cape-Manager, der Overlays zur Laufzeit nachlädt. Jede Pin- oder Peripherie-Änderung bedeutet also: Basis-.dts erweitern (oder eine eigene Variante ableiten), Kernel neu bauen, neues .dtb deployen.

Die Basisdatei für die BeagleBone Black liegt im Kernel-Quellbaum unter:

arch/arm/boot/dts/am335x-boneblack.dts

Sie bindet u. a. am33xx.dtsi (SoC-Definition) und am335x-bone-common.dtsi (gemeinsame Pins/Peripherie von Bone-Varianten) ein. Für eigene Anpassungen bietet sich an, eine eigene .dts zu schreiben, die die Basis per #include einbindet und gezielt Knoten per &label { …​ } überschreibt oder ergänzt — dieselbe Syntax, die auch in echten Overlays verwendet wird, hier aber statisch zur Build-Zeit aufgelöst.

Beispiel: UART4 (Pins P9.11 = RX, P9.13 = TX) ist auf der BeagleBone Black per Default deaktiviert und ohne passenden Pinmux nicht nutzbar. Aktivierung in am335x-boneblack-mybbb.dts:

/dts-v1/;

#include "am335x-boneblack.dts"

&am33xx_pinmux {
    uart4_pins: pinmux_uart4_pins {
        pinctrl-single,pins = <
            AM33XX_PADCONF(AM335X_PIN_SPI0_CS0, PIN_INPUT_PULLUP, MUX_MODE6)  /* uart4_rxd.P9_11 */
            AM33XX_PADCONF(AM335X_PIN_SPI0_D0, PIN_OUTPUT_PULLDOWN, MUX_MODE6) /* uart4_txd.P9_13 */
        >;
    };
};

&uart4 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&uart4_pins>;
};

Die Werte für PIN_INPUT_PULLUP/MUX_MODE6 etc. stammen aus am33xx.h/pinctrl-single.h; welcher Mode welche Funktion auf einem Pin freischaltet, steht im AM335x Technical Reference Manual (Tabelle „Pin Mux Modes“) — beim Ändern von Pins immer dort nachschlagen, statt Werte zu raten.

Damit die Datei beim Kernel-Build auch am richtigen Ort landet — KERNEL_DEVICETREE erwartet sie unterhalb von arch/arm/boot/dts/ im Quellbaum —, kopiert das .bbappend sie in do_configure:append():

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://am335x-boneblack-mybbb.dts"

do_configure:append() {
    cp ${WORKDIR}/am335x-boneblack-mybbb.dts \
        ${S}/arch/arm/boot/dts/
}

KERNEL_DEVICETREE:append = " am335x-boneblack-mybbb.dtb"

Bauen und das Ergebnis prüfen:

bitbake virtual/kernel

Nach dem Build liegt das neue .dtb unter tmp/deploy/images/beaglebone-yocto/am335x-boneblack-mybbb.dtb und muss beim SD-Karten-Setup (Step 9) anstelle des Standard-.dtb nach /boot/ kopiert werden. Auf dem laufenden System lässt sich verifizieren, ob der Device Tree wie erwartet geladen wurde:

cat /proc/device-tree/model
ls /sys/bus/platform/devices/ | grep 481aa000   # UART4-Basisadresse (AM335x TRM)
dmesg | grep -i uart4

Ein dtc-Syntaxfehler zeigt sich meist erst beim Kernel-Build als kryptischer Bison/Flex-Fehler. Für schnelle Iteration lohnt es sich, die .dts isoliert mit dem Device-Tree-Compiler zu prüfen, bevor ein voller bitbake virtual/kernel-Lauf gestartet wird:

dtc -I dts -O dtb -o /dev/null \
    -i arch/arm/boot/dts \
    arch/arm/boot/dts/am335x-boneblack-mybbb.dts

14.4. systemd Services integrieren

Yocto nutzt standardmäßig SysVinit; für systemd müssen DISTRO_FEATURES und der Init-Manager gesetzt werden, z. B. in conf/local.conf:

DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = ""

Eine eigene Recipe kann dann eine .service-Unit ausliefern:

# mydaemon_1.0.bb
inherit systemd

SYSTEMD_SERVICE:${PN} = "mydaemon.service"
SYSTEMD_AUTO_ENABLE = "enable"

SRC_URI += "file://mydaemon.service"

do_install:append() {
    install -d ${D}${systemd_system_unitdir}
    install -m 0644 ${WORKDIR}/mydaemon.service ${D}${systemd_system_unitdir}
}
# mydaemon.service
[Unit]
Description=My Daemon

[Service]
ExecStart=/usr/bin/mydaemon

[Install]
WantedBy=multi-user.target

14.5. Ethernet konfigurieren

Mit systemd als Init-System übernimmt üblicherweise systemd-networkd die Netzwerkkonfiguration. Eine statische IP für die BeagleBone-Black-Ethernet-Schnittstelle lässt sich per .network-Datei ausliefern:

# 10-eth0.network
[Match]
Name=eth0

[Network]
Address=192.168.7.2/24
Gateway=192.168.7.1
DNS=192.168.7.1

Recipe dazu:

SRC_URI += "file://10-eth0.network"

do_install:append() {
    install -d ${D}${sysconfdir}/systemd/network
    install -m 0644 ${WORKDIR}/10-eth0.network ${D}${sysconfdir}/systemd/network
}

systemd-networkd muss dafür in DISTRO_FEATURES bzw. den Image-Paketen aktiv sein (systemd-networkd, systemd-resolved je nach Bedarf in IMAGE_INSTALL ergänzen).

14.6. PRU-Entwicklung

Die BeagleBone Black besitzt zwei PRU-ICSS-Coprozessoren (PRU0, PRU1) für harte Echtzeitanforderungen — etwa präzises Timing auf GPIOs, jenseits dessen was Linux garantieren kann. Für Yocto-Builds bringt das meta-ti-Layer (meta-ti-bsp) die nötige Toolchain und Support-Pakete mit:

git clone https://git.yoctoproject.org/meta-ti
cd meta-ti
git checkout kirkstone
cd ..

bitbake-layers add-layer ../meta-ti/meta-ti-bsp

PRU-Firmware wird als eigenständiges Programm mit dem pru-software-support-package bzw. dem ti-cgt-pru-Compiler gebaut und über eine Recipe ausgeliefert, die deploy und die remoteproc-Firmware-Konvention nutzt:

SRC_URI = "file://pru-blink.c"

do_compile() {
    pru-cgt -v3 -o pru-blink.out pru-blink.c
}

do_install() {
    install -d ${D}/lib/firmware
    install -m 0644 pru-blink.out ${D}/lib/firmware/am335x-pru0-fw
}

FILES:${PN} += "/lib/firmware/am335x-pru0-fw"

Zur Laufzeit lädt der Linux-remoteproc-Treiber die Firmware und startet den PRU-Kern:

echo stop > /sys/class/remoteproc/remoteproc1/state
echo am335x-pru0-fw > /sys/class/remoteproc/remoteproc1/firmware
echo start > /sys/class/remoteproc/remoteproc1/state

Kommunikation zwischen PRU und Linux läuft dann typischerweise über rpmsg oder geteilten Shared Memory (PRU-Interrupt-Controller).