it-swarm.com.de

Wie führe ich ein C-Programm ohne Betriebssystem auf dem Raspberry Pi aus?

Ich würde gerne mit dem Raspberry Pi für einige verschiedene Embedded-Anwendungen experimentieren. Das einzige Problem ist, dass Raspberry Pi im Gegensatz zu den verfügbaren AVR- und PIC-Mikrocontroller-Karten normalerweise ein Betriebssystem (wie Raspbian) ausführt, das die CPU-Zeit auf alle laufenden Programme verteilt und für bestimmte Echtzeitanwendungen unpraktisch macht.

Ich habe kürzlich erfahren, dass, vorausgesetzt, Sie haben einen Bootloader wie GRUB) installiert, das Ausführen eines C-Programms auf x86 (in Form eines Kernels) nur sehr wenig Zeit in Anspruch nimmt Setup, nur ein Assembly-Programm zum Aufrufen der Hauptfunktion und des tatsächlichen C-Codes.

Gibt es eine Möglichkeit, dies mit einem Himbeer-Pi zu erreichen? Es wäre eine großartige Möglichkeit, etwas über Low Level ARM Programmierung zu lernen, und es gibt bereits einige komplexe Peripheriegeräte, mit denen man herumspielen kann (USB, Ethernet usw.).

36
watswat5

Obwohl Bare Metal auf dem Pi möglich ist, würde ich es vermeiden, da Linux so leicht wird und eine ganze Reihe von Dingen für Sie erledigt.

Hier ist ein Tutorial, um Ihnen den Einstieg zu erleichtern, wenn Sie noch Bare-Metal-Sachen lernen möchten: http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1 /

Nach alledem würde ich einfach Ihre bevorzugte eingebettete Linux-Distribution laden (RT-Patches werden je nach Ihren Anforderungen bevorzugt) und als gut bezeichnen.

15
It'sPete

Beispiel für einen vollautomatischen Minimal-Bare-Metal-Blinker

Getestet auf Ubuntu 16.04 Host, Raspberry Pi 2.

dwelchs ist das umfassendste Beispiel , aber dies ist eine minimal einfach einzurichtende Hallo Welt.

Verwendung:

  1. Legen Sie eine SD-Karte in den Host ein

  2. Mach das Bild:

    ./make.sh /dev/mmblck0 p1
    

    Woher:

    • /dev/mmblck0 Ist das Gerät der SD-Karte
    • p1 Ist die erste Partition des Geräts (/dev/mmblck0p1)
  3. Legen Sie die SD-Karte in PI ein

  4. Schalten Sie das Gerät aus und wieder ein

enter image description here

GitHub upstream: https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker/tree/d20f0337189641824b3ad5e4a688aa91e13fd764

start.S

.global _start
_start:
    mov sp, #0x8000
    bl main
hang:
    b hang

haupt c

#include <stdint.h>

/* This is bad. Anything remotely serious should use timers
 * provided by the board. But this makes the code simpler. */
#define BUSY_WAIT __asm__ __volatile__("")
#define BUSY_WAIT_N 0x100000

int main( void ) {
    uint32_t i;
    /* At the low level, everything is done by writing to magic memory addresses.
    The device tree files (dtb / dts), which are provided by hardware vendors,
    tell the Linux kernel about those magic values. */
    volatile uint32_t * const GPFSEL4 = (uint32_t *)0x3F200010;
    volatile uint32_t * const GPFSEL3 = (uint32_t *)0x3F20000C;
    volatile uint32_t * const GPSET1  = (uint32_t *)0x3F200020;
    volatile uint32_t * const GPCLR1  = (uint32_t *)0x3F20002C;

    *GPFSEL4 = (*GPFSEL4 & ~(7 << 21)) | (1 << 21);
    *GPFSEL3 = (*GPFSEL3 & ~(7 << 15)) | (1 << 15);
    while (1) {
        *GPSET1 = 1 << (47 - 32);
        *GPCLR1 = 1 << (35 - 32);
        for (i = 0; i < BUSY_WAIT_N; ++i) { BUSY_WAIT; }
        *GPCLR1 = 1 << (47 - 32);
        *GPSET1 = 1 << (35 - 32);
        for (i = 0; i < BUSY_WAIT_N; ++i) { BUSY_WAIT; }
    }
}

ldscript

MEMORY
{
    ram : Origin = 0x8000, LENGTH = 0x10000
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}

make.sh

#!/usr/bin/env bash

set -e

dev="${1:-/dev/mmcblk0}"
part="${2:-p1}"
part_dev="${dev}${part}"
mnt='/mnt/rpi'

Sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi

# Generate kernel7.img
arm-none-eabi-as start.S -o start.o
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -c main.c -o main.o
arm-none-eabi-ld start.o main.o -T ldscript -o main.elf
# Get the raw Assembly out of the generated elf file.
arm-none-eabi-objcopy main.elf -O binary kernel7.img

# Get the firmware. Those are just magic blobs, likely compiled
# from some Broadcom proprietary C code which we cannot access.
wget -O bootcode.bin https://github.com/raspberrypi/firmware/blob/597c662a613df1144a6bc43e5f4505d83bd748ca/boot/bootcode.bin?raw=true
wget -O start.elf https://github.com/raspberrypi/firmware/blob/597c662a613df1144a6bc43e5f4505d83bd748ca/boot/start.elf?raw=true

# Prepare the filesystem.
Sudo umount "$part_dev"
echo 'start=2048, type=c' | Sudo sfdisk "$dev"
Sudo mkfs.vfat "$part_dev"
Sudo mkdir -p "$mnt"
Sudo mount "${part_dev}" "$mnt"
Sudo cp kernel7.img bootcode.bin start.elf "$mnt"

# Cleanup.
sync
Sudo umount "$mnt"

QEMU-freundliche Bare-Metal-Beispiele

Das Problem mit dem Blinker ist, dass es schwierig ist, LEDs in QEMU zu beobachten: https://raspberrypi.stackexchange.com/questions/56373/is-it-possible-to-get-the-state-of- die-leds-und-gpios-in-a-qemu-emulation-like-t

Hier beschreibe ich einige Bare-Metal-QEMU-Setups, die von Interesse sein könnten: Wie erstelle ich Bare-Metal-Programme ARM und führe sie auf QEMU aus? Das Schreiben auf UART ist der einfachste Weg um die Ausgabe von QEMU zu erhalten.

Bonus

Hier ist ein x86-Beispiel für Neugierige: Wie starte ich ein Programm ohne Betriebssystem?

https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ ist ein großartiges Tutorial, und wie Sie sehen werden, ist es die beste Möglichkeit, Code schnell und schmutzig auszuführen Auf Bare Metal müssen Sie eine Linux-Distribution hijacken. Kompilieren Sie dazu einfach kernel.img (mit den entsprechenden Architekturoptionen) und ersetzen Sie die in der Linux-Distribution vorhandene Distribution für diesen Abschnitt des Tutorials, den Sie aufrufen können : https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html#pitime

3
joshbooks

Der Pi ist möglicherweise etwas suboptimal für das, was Sie tun möchten, da das SoC-Design so ausgelegt ist, dass die ARM CPU ein Bürger zweiter Klasse ist - das heißt, es gibt einige Rahmen, durch die Sie springen müssen Holen Sie sich ein Bare-Metal-Programm auf.

Sie können jedoch etwas schummeln und die -Boot-API verwenden, um Zugriff auf einige der von U-Boot bereitgestellten Funktionen zu erhalten. Sie können jedoch auch eigene Funktionen hinzufügen.

2
unixsmurf