我想在一些不同的低级别嵌入式应用程序中使用Raspberry Pi进行实验。唯一的问题是,与现有的AVR和PIC微控制器板不同,Raspberry Pi通常运行一个操作系统(如Raspbian),它在所有运行的程序中分配CPU时间,使得某些实时应用程序不切实际。
最近我了解到,假设安装了像GRUB这样的引导加载程序,那么在x86 (以内核的形式)上运行C程序只需要很少的实际设置,只需要一个程序集来调用主函数和实际的C代码。
有没有办法用树莓Pi来达到这个目的?这将是学习底层ARM编程的一个很好的方法,而且它已经有一些复杂的外围设备可以处理(USB、以太网等)。
发布于 2016-10-15 10:59:55
全自动最小裸金属闪光灯示例
在Ubuntu 16.04寄主Raspberry Pi 2上进行了测试。
https://github.com/dwelch67/raspberrypi是我迄今所见过的最全面的示例集(在本现在删除答案中已经提到过),但是这是一个很容易设置hello以使您快速入门的示例集。
用法:
- `/dev/mmblck0` is the device of the SD card
- `p1` is the first partition of the device (`/dev/mmblck0p1`)
start.S
.global _start
_start:
mov sp, #0x8000
bl main
hang:
b hang
main.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友好裸金属示例
闪光灯的问题是很难观察到QEMU:https://raspberrypi.stackexchange.com/questions/56373/is-it-possible-to-get-the-state-of-the-leds-and-gpios-in-a-qemu-emulation-like-t中的发光二极管。
在这里,我描述了一些可能感兴趣的裸金属QEMU设置:如何制作裸金属臂程序并在QEMU上运行?写入UART是从QEMU获得输出的最简单方法。
QEMU在多大程度上模拟了Raspberry Pi,这部分可以从以下几个方面推断出来:如何用QEMU模拟Raspberry Pi Raspbian?,因为即使是Linux终端也会出现,很可能你的裸金属设备也能工作。
奖金
下面是一个好奇者的x86示例:如何在没有操作系统的情况下运行程序?
发布于 2015-04-23 19:00:36
虽然在Pi上裸金属是可能的,但我会避免它,因为Linux变得如此轻量级,并且为您处理了大量的东西。
如果您还想学习裸金属材料,这里有一个教程可以让您开始学习:http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/
尽管如此,我还是会加载您最喜欢的嵌入式linux发行版(根据您的需求,RT修补可能是首选的),并称其为好版本。
发布于 2015-04-23 19:17:09
https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/是一个很好的教程,他们会告诉您,在裸金属上运行代码的最好方法是劫持linux发行版,要做到这一点,只需编译到kernel.img (有适当的体系结构选项),并使用它来替换linux发行版中现有的版本,这部分教程就是:https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html#pitime。
https://stackoverflow.com/questions/29837892
复制