¿Cómo ejecutar un programa C sin sistema operativo en la Raspberry Pi?
Me gustaría experimentar usando Raspberry Pi para algunas aplicaciones embebidas de bajo nivel diferentes. El único problema es que, a diferencia de las placas de microcontroladores AVR y PIC disponibles, Raspberry Pi normalmente ejecuta un sistema operativo (como Raspbian) que distribuye el tiempo de CPU a través de todos los programas en ejecución y lo hace poco práctico para ciertas aplicaciones en tiempo real.
He aprendido recientemente que, suponiendo que tiene un gestor de arranque como GRUB instalado, ejecutando un programa C en x86 (en forma de un kernel) toma muy poca configuración real, solo un programa ensamblador para llamar a la función principal y el código C real.
¿Hay alguna manera de lograr esto con una Raspberry Pi? Sería una gran manera de aprender sobre la programación ARM de bajo nivel, y ya tiene algunos periféricos complejos para jugar (USB, Ethernet,etc.)
5 answers
Mientras que bare metal es posible en la Pi, yo lo evitaría ya que Linux se está volviendo muy ligero y maneja un montón de cosas para usted.
Aquí hay un tutorial para comenzar si aún quieres aprender cosas de metal desnudo: http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1/
Con todo lo dicho, simplemente cargaría su distro de Linux incrustado favorito (RT parcheado podría ser preferido en función de sus requisitos) y lo llamaría Bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-24 03:00:36
En realidad, la Raspberry Pi es uno de los brazos más fáciles de programar bare metal (sin sistema operativo) Tengo muchos ejemplos en github para comenzar
Https://github.com/dwelch67/raspberrypi
Una cosa buena sobre raspberry pi es que no necesita un gestor de arranque como uboot, hay una gpu que realmente trae el chip primero y luego carga el núcleo (o la aplicación bare metal, lo que sea) en ram y se ramifica de la misma manera que uboot tendría. Otra cosa agradable es que usted no puede ladrillo como usted puede con tantos otros tableros en esta clase, si se equivoca usted tira de la tarjeta sd, inténtelo de nuevo, si se da por vencido a continuación, poner una tarjeta sd con Linux en él de nuevo y ejecutar linux...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-14 15:05:16
Ejemplo de intermitente de metal desnudo mínimo totalmente automatizado
Probado en Ubuntu 16.04 host, Raspberry Pi 2.
Dwelch es el ejemplo más completo, pero este es un mínimo fácil de configurar hello world.
Uso:
-
Inserte la tarjeta SD en el host
-
Haz la imagen:
./make.sh /dev/mmblck0 p1
Donde:
-
/dev/mmblck0
es el dispositivo de la tarjeta SD -
p1
es la primera partición del dispositivo (/dev/mmblck0p1
)
-
-
Insertar tarjeta SD en PI
-
Apagar y encender
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
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"
Ejemplos de QEMU friendly bare metal
El problema con el intermitente es que es difícil observar ledes en 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
Aquí describo algunas configuraciones de QEMU de metal desnudo que pueden ser de interés: ¿Cómo hacer programas de brazo de metal desnudo y ejecutarlos en QEMU? Escribir en el UART es la forma más fácil de obtener la salida de QEMU.
Bonus
Aquí hay un ejemplo de x86 para los curiosos: Cómo ejecutar un programa sin un sistema operativo?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-22 06:08:12
Https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os / es un gran tutorial, y como te dirán la mejor manera rápida y sucia de ejecutar código en bare metal es secuestrar una distribución de linux, para hacerlo, solo compila al núcleo.img (con las opciones de arquitectura apropiadas) y utilícela para reemplazar la existente en la distribución de linux solo para esta sección del tutorial puede ir a: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html#pitime
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-24 03:17:09
El Pi puede ser un poco subóptimo para lo que desea hacer, ya que el diseño SoC es tal que la CPU ARM es un ciudadano de segunda clase, lo que significa que hay algunos aros para saltar para obtener un programa de metal desnudo ejecutándose en él.
Sin embargo, podría hacer trampa un poco y usar la API U-Boot para darle acceso a algunas de las características que U-Boot proporciona, pero ser capaz de agregar sus propias características en el lateral.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-24 10:27:00