Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raspberry Pi 4B & 5 baremetal blink example #67

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5c16244
Create README.md
iCMDdev Oct 26, 2024
d7ee0fb
Update README.md
iCMDdev Oct 26, 2024
b82c7f1
Added Blink example code
iCMDdev Oct 26, 2024
595b02e
Update MainApp.swift
iCMDdev Oct 26, 2024
6f680c0
Delete RPi4B-blink/Makefile
iCMDdev Oct 26, 2024
b15606f
Update link.ld
iCMDdev Oct 26, 2024
555bdbd
Update boot.S
iCMDdev Oct 26, 2024
6e9cf61
Add files via upload
iCMDdev Oct 26, 2024
0fd00dd
Update build.sh
iCMDdev Oct 26, 2024
bd61e35
Update link.ld
iCMDdev Oct 26, 2024
c4ea37d
Added RPi 5 example
iCMDdev Oct 27, 2024
72347f6
Delete rpi5-blink/Package.resolved
iCMDdev Oct 27, 2024
7a9af2f
Delete RPi4B-blink directory
iCMDdev Oct 27, 2024
f8f64ae
Updated RPi 4 example
iCMDdev Oct 27, 2024
ec9afca
Simplified README.md (removed redundent chmod command)
iCMDdev Oct 27, 2024
9403cb3
Added LLVM instructions
iCMDdev Oct 27, 2024
471c4a5
Update description
iCMDdev Oct 27, 2024
b2e3601
Typo fix
iCMDdev Oct 27, 2024
f560449
Merge branch 'main' into RPi-4B-BCM2711
iCMDdev Dec 12, 2024
8f1ca70
Update pico-w-blink-sdk README.md
iCMDdev Dec 13, 2024
7451fe2
Added CI support
iCMDdev Dec 13, 2024
7426575
Merge pull request #3 from iCMDdev/RPi-4B-BCM2711
iCMDdev Dec 13, 2024
e9a3971
Update build-rpi-baremetal.yml
iCMDdev Dec 13, 2024
c60a427
Rename workflow
iCMDdev Dec 13, 2024
f768d03
Update build-rpi-baremetal.yml
iCMDdev Dec 13, 2024
669fcc8
Update build-rpi-baremetal.yml
iCMDdev Dec 13, 2024
30def4e
Update build-rpi-baremetal.yml
iCMDdev Dec 13, 2024
e7076ae
Update build-rpi-baremetal.yml
iCMDdev Dec 13, 2024
0dee67c
Makefile typo fix
iCMDdev Dec 13, 2024
290c928
Merge pull request #5 from iCMDdev/RPi-4B-BCM2711
iCMDdev Dec 13, 2024
a6e2b92
Makefile fixes
iCMDdev Dec 13, 2024
ce46d5e
Merge pull request #6 from iCMDdev/RPi-4B-BCM2711
iCMDdev Dec 13, 2024
bda28bb
Makefile fixes for Linux host
iCMDdev Dec 13, 2024
b1c238c
Merge pull request #7 from iCMDdev/RPi-4B-BCM2711
iCMDdev Dec 13, 2024
92b775c
Fix styling
iCMDdev Dec 13, 2024
b677708
Update README.md
iCMDdev Dec 13, 2024
47894c7
Merge branch 'main' into RPi-4B-BCM2711
iCMDdev Dec 15, 2024
7f99773
Update build-rpi-baremetal.yml
iCMDdev Dec 15, 2024
3e623d8
Merge branch 'main' into RPi-4B-BCM2711
iCMDdev Dec 15, 2024
c202dd5
Merge branch 'main' into RPi-4B-BCM2711
iCMDdev Dec 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/build-rpi-baremetal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build Raspberry Pi Baremetal Examples

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
# Build on Mondays at 9am PST every week
- cron: '0 17 * * 1'

jobs:
build-pico-sdk:
runs-on: ubuntu-22.04
container: swiftlang/swift:nightly-main-jammy
strategy:
fail-fast: false
matrix:
example: [rpi5-blink, rpi4b-blink]

steps:
- name: Checkout repo
uses: actions/checkout@v4

- name: Install apt dependencies
run: apt-get -qq update && apt-get -qq -y install make llvm

- name: Build ${{ matrix.example }}
run: |
cd ${{ matrix.example }}
make
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Each example in this repository contains build and deployment instructions, howe
| [nrfx-blink-sdk](./nrfx-blink-sdk) | nRF52840-DK | Zephyr SDK | Blink an LED repeatedly with Swift & Zephyr. | <img width="300" src="https://github.com/apple/swift-embedded-examples/assets/1186214/ae3ff153-dd33-4460-8a08-4eac442bf7b0"> |
| [esp32-led-strip-sdk](./esp32-led-strip-sdk) | ESP32-C6-DevKitC-1 | ESP-IDF SDK | Control NeoPixel LEDs with Swift & the ESP-IDF. | <img width="300" src="https://github.com/apple/swift-embedded-examples/assets/1186214/15f8a3e0-953e-426d-ad2d-3902baf859be"> |
| [esp32-led-blink-sdk](./esp32-led-blink-sdk) | ESP32-C6-Bug | ESP-IDF SDK | Blink an LED repeatedly with Swift & the ESP-IDF. | <img width="300" src="esp32-led-blink-sdk/assets/images/ledon.jpg"> |
| [rpi4b-blink](./rpi4b-blink) | Raspberry Pi 4B | None | Blink the Pi's status green LED repeatedly using Swift MMIO. | <img width="300" src="rpi4b-blink/assets/rpi4.png"> |
| [rpi5-blink](./rpi5-blink) | Raspberry Pi 5 | None | Blink the Pi's status green LED repeatedly with Swift MMIO. | <img width="300" src="rpi5-blink/assets/raspi5.png"> |

Note that the SDK integration examples (Pico SDK, Zephyr SDK, etc.) are not recommendations or endorsement, the same is true for build system choice (Make, CMake, SwiftPM, shell scripts). Embedded Swift aims to be versatile and to allow for integration into more existing SDKs and build systems, and the example projects are merely showing the possibilities.

Expand Down
28 changes: 28 additions & 0 deletions rpi4b-blink/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi)
CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi)
LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi)

BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path)

.PHONY: all clean

all: kernel8.img

kernel8.img: kernel8.elf
@echo "💾 Converting to binary kernel image with llvm-objcopy..."
$(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img
@echo ""
@echo "🥳 Done! kernel8.img was saved to this directory."

kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld
@echo "🔗 Linking with clang..."
$(CLANG) --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld
@echo ""

$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o:
@echo "🛠️ Building with Swift Package Manager..."
$(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector
@echo ""

clean:
rm -rf kernel8.elf kernel8.img .build
36 changes: 36 additions & 0 deletions rpi4b-blink/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "RPi4B-Blink",
platforms: [
.macOS(.v14)
],
products: [
.library(
name: "MainApp",
type: .static,
targets: ["MainApp"])
],
dependencies: [
.package(
url: "https://github.com/apple/swift-mmio.git",
branch: "swift-embedded-examples")
],
targets: [
.target(
name: "MainApp",
dependencies: [
.product(name: "MMIO", package: "swift-mmio")
],
swiftSettings: [
.enableExperimentalFeature("Embedded"),
.unsafeFlags(["-Xfrontend", "-function-sections"]),
]
),
.target(name: "Support"),

]
)
24 changes: 24 additions & 0 deletions rpi4b-blink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# rpi4b-blink

<img src="assets/rpi4.png">

## Requirements

- A Raspberry Pi 4B board
- An SD Card, with a Raspberry Pi OS installed (this way, we don't need to create the configuration files from scratch). You may backup `kernel8.img` and `config.txt` if you need the Linux install later, since we will change these files.
- LLVM installed (`brew install llvm`) and added to PATH. This is needed to convert the resulted ELF file to binary image format using `llvm-objcopy`.

## How to build and run this example:

- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support.
- Build the program, then copy the kernel image to the SD card.
``` console
$ cd rpi4b-blink
$ export TOOLCHAINS='<toolchain-identifier>' # Your Swift nightly toolchain identifier
$ make
$ cp kernel8.img /Volumes/bootfs
```
- If your original OS is not 64-bit, make sure to set `arm_64bit=1` in `config.txt`.
- Place the SD card in your Raspberry Pi 4B, and connect it to power.
- After the boot sequence, the green (ACT) led will start blinking in a regular pattern.

82 changes: 82 additions & 0 deletions rpi4b-blink/Sources/MainApp/MainApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors.
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import MMIO

@Register(bitWidth: 32)
struct GPSET1 {
@ReadWrite(bits: 10..<11, as: Bool.self)
var set: SET
}

@Register(bitWidth: 32)
struct GPCLR1 {
@ReadWrite(bits: 10..<11, as: Bool.self)
var clear: CLEAR
}

@Register(bitWidth: 32)
struct GPFSEL4 {
@ReadWrite(bits: 6..<7, as: Bool.self)
var fsel42b1: FSEL42b1
@ReadWrite(bits: 7..<8, as: Bool.self)
var fsel42b2: FSEL42b2
@ReadWrite(bits: 8..<9, as: Bool.self)
var fsel42b3: FSEL42b3
}

@RegisterBlock
struct GPIO {
@RegisterBlock(offset: 0x200020)
var gpset1: Register<GPSET1>
@RegisterBlock(offset: 0x20002c)
var gpclr1: Register<GPCLR1>
@RegisterBlock(offset: 0x200010)
var gpfsel4: Register<GPFSEL4>
}

let gpio = GPIO(unsafeAddress: 0xFE00_0000)

func setLedOutput() {
gpio.gpfsel4.modify {
// setFunction Select 42 (fsel42) to 001
$0.fsel42b1 = true
$0.fsel42b2 = false
$0.fsel42b3 = false
}
}

func ledOn() {
gpio.gpset1.modify {
$0.set = true
}
}

func ledOff() {
gpio.gpclr1.modify {
$0.clear = true
}
}

@main
struct Main {

static func main() {
setLedOutput()

while true {
ledOn()
for _ in 1..<100000 {} // just a delay
ledOff()
for _ in 1..<100000 {} // just a delay
}
}
}
41 changes: 41 additions & 0 deletions rpi4b-blink/Sources/Support/boot.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors.
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

.section ".text.boot"

.global _start

_start:
// Check processor ID is zero (executing on main core), else hang
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// We're not on the main core, so hang in an infinite wait loop
1: wfe
b 1b
2: // We're on the main core!

// Set stack to start below our code
ldr x1, =_start
mov sp, x1

// Clean the BSS section
ldr x1, =__bss_start // Start address
ldr w2, =__bss_size // Size of the section
3: cbz w2, 4f // Quit loop if zero
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b // Loop if non-zero

// Jump to Swift!
4: bl main
// Halt if Swift returns
b 1b
Empty file.
Binary file added rpi4b-blink/assets/rpi4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions rpi4b-blink/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SECTIONS
{
. = 0x80000; /* Kernel load address for AArch64 */
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;

/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;
28 changes: 28 additions & 0 deletions rpi5-blink/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi)
CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi)
LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi)

BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path)

.PHONY: all clean

all: kernel8.img

kernel8.img: kernel8.elf
@echo "💾 Converting to binary kernel image with llvm-objcopy..."
$(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img
@echo ""
@echo "🥳 Done! kernel8.img was saved to this directory."

kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld
@echo "🔗 Linking with clang..."
$(CLANG) --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld
@echo ""

$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o:
@echo "🛠️ Building with Swift Package Manager..."
$(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector
@echo ""

clean:
rm -rf kernel8.elf kernel8.img .build
33 changes: 33 additions & 0 deletions rpi5-blink/Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"originHash" : "193ca3f107e2c8dd2da5d091f6259f64b2cbfd6776d1c26bbcfb195b3a0b5045",
"pins" : [
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
"version" : "1.5.0"
}
},
{
"identity" : "swift-mmio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-mmio.git",
"state" : {
"branch" : "swift-embedded-examples",
"revision" : "06d96ed4916739f2edafde87f3951b2d2a04df65"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swiftlang/swift-syntax.git",
"state" : {
"revision" : "0687f71944021d616d34d922343dcef086855920",
"version" : "600.0.1"
}
}
],
"version" : 3
}
36 changes: 36 additions & 0 deletions rpi5-blink/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "RPi5-Blink",
platforms: [
.macOS(.v14)
],
products: [
.library(
name: "MainApp",
type: .static,
targets: ["MainApp"])
],
dependencies: [
.package(
url: "https://github.com/apple/swift-mmio.git",
branch: "swift-embedded-examples")
],
targets: [
.target(
name: "MainApp",
dependencies: [
.product(name: "MMIO", package: "swift-mmio")
],
swiftSettings: [
.enableExperimentalFeature("Embedded"),
.unsafeFlags(["-Xfrontend", "-function-sections"]),
]
),
.target(name: "Support"),

]
)
Loading
Loading