web-dev-qa-db-ja.com

Raspberry PiでOSなしでCプログラムを実行する方法は?

いくつかの異なる低レベルの組み込みアプリケーションでRaspberry Piを使用して実験したいと思います。唯一の問題は、利用可能なAVRおよびPICマイクロコントローラーボードとは異なり、Raspberry Piは通常、実行中のすべてのプログラムにCPU時間を分散するOS(Raspbianなど)を実行し、特定のリアルタイムアプリケーションに対して非実用的にすることです。

私は最近、GRUBのようなブートローダーがインストールされていると仮定して、x86でCプログラムを実行 (カーネルの形式で) は実際にはほとんどかかりません。セットアップ、メイン関数と実際のCコードを呼び出すアセンブリプログラムのみ。

Raspberry Piでこれを実現する方法はありますか?低レベルARMプログラミングについて学習するのに最適な方法であり、既にいくつかの複雑な周辺機器(USB、イーサネットなど)をいじる必要があります)

36
watswat5

Piではベアメタルを使用できますが、Linuxが非常に軽量になり、あらゆるものを処理するため、それを回避します。

ベアメタルの内容を引き続き学習したい場合に始めるためのチュートリアルを次に示します。 http://www.valvers.com/open-software/raspberry-pi/step01-bare-metal-programming-in-cpt1 /

とは言っても、お気に入りの組み込みLinuxディストリビューションをロードして(要件に応じてRTパッチを適用することをお勧めします)、それを適切なものと呼びます。

15
It'sPete

完全に自動化された最小限のベアメタルブリンカーの例

Ubuntu 16.04ホスト、Raspberry Pi 2でテスト済み。

dwelch'sが最も包括的な例 ですが、これはセットアップが簡単なHello Worldです。

使用法:

  1. ホストにSDカードを挿入

  2. 画像を作成します。

    ./make.sh /dev/mmblck0 p1
    

    どこで:

    • /dev/mmblck0はSDカードのデバイスです
    • p1はデバイスの最初のパーティションです(/dev/mmblck0p1
  3. PIの挿入SDカード

  4. 電源を入れ直します

enter image description here

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 <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でLEDを観察するのが難しいことです: 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セットアップについて説明します。 ベアメタルARMプログラムを作成してQEMUで実行する方法 UARTへの書き込みQEMUから出力を取得する最も簡単な方法です。

ボーナス

好奇心の強い人のためのx86の例を次に示します。 オペレーティングシステムなしでプログラムを実行する方法

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

3
joshbooks

SoCの設計ではARM CPUは二流の市民であるため、ジャンプするにはいくつかのフープがあることを意味するため、Piは実行したいことに対して少し準最適な場合がありますベアメタルプログラムを実行します。

ただし、少しごまかして -Boot API を使用すると、U-Bootが提供する機能の一部にアクセスできますが、独自の機能をサイドに追加できます。

2
unixsmurf