如何在Raspberry Pi上运行没有操作系统的C程序?

我想尝试将Raspberry Pi用于一些不同的低级嵌入式应用程序。 唯一的问题是,与可用的AVR和PIC微控制器板不同,Raspberry Pi通常运行一个操作系统(如Raspbian),它在所有正在运行的程序中分配CPU时间,并使其对某些实时应用程序不切实际。

我最近了解到,假设你有一个像GRUB一样的bootloader,在x86上运行一个C程序(以内核的forms)只需要很少的实际设置,只需要一个汇编程序来调用main函数和实际的C代码。

有没有办法用Raspberry Pi实现这一目标? 这是学习低级ARM编程的好方法,它已经有一些复杂的外围设备(USB,以太网等)

虽然在Pi上可以使用裸机,但我会避免使用它,因为Linux变得如此轻量级并为您处理了大量内容。

如果您还想学习裸机,可以使用以下教程: http : //www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/

尽管如此,我还是会加载您最喜欢的嵌入式Linux发行版(根据您的要求,RT补丁可能是首选)并称之为好。

实际上Raspberry Pi是编程裸机的更容易的武器之一(没有操作系统)我在github上有很多例子可以让你入门

https://github.com/dwelch67/raspberrypi

关于raspberry pi的一个好处是它不需要像uboot这样的引导加载程序,有一个gpu实际上首先将芯片加载然后它将内核(或裸机应用程序,无论如何)加载到ram中并在其中分支到它。与uboot相同的方式。 另一个好处是你不能像这样在同类课程中使用这么多其他电路板,如果你搞砸了你把SD卡拿出来,再试一次,如果你放弃然后把一个带有linux的SD卡放回来和运行linux …

完全自动化的最小裸金属闪光灯示例

在Ubuntu 16.04主机上测试,Raspberry Pi 2。

dwelch是最全面的例子 ,但这是一个简单易用的hello世界。

用法:

  1. 在主机上插入SD卡

  2. 制作图片:

    ./make.sh /dev/mmblck0 p1 

    哪里:

    • /dev/mmblck0是SD卡的设备
    • p1是设备的第一个分区( /dev/mmblck0p1
  3. 在PI上插入SD卡

  4. 关闭电源然后再打开电源

在此处输入图像描述

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

start.S中

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

main.c中

 #include  /* 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友好的裸机示例

闪光灯的问题是在QEMU中很难观察到LED: https : //raspberrypi.stackexchange.com/questions/56373/is-it-possible-to-get-the-state-of-the-leds-和个GPIO-IN-A-QEMU仿真样-T

在这里,我描述了一些可能感兴趣的裸机QEMU设置: 如何制作裸机ARM程序并在QEMU上运行它们? 写入UART是从QEMU输出输出的最简单方法。

奖金

这是一个奇怪的x86示例: 如何在没有操作系统的情况下运行程序?

对于你想要做的事情,Pi可能有点不理想,因为SoC设计使ARM CPU成为二等公民 – 这意味着有一些环节可以跳过来运行裸机程序。

但是,您可以作弊并使用U-Boot API来访问U-Boot提供的一些function,但是可以在侧面添加您自己的function。