1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#![no_std]
#![no_main]
// Mini-UART (UART1) "hello world" on GPIO14/15, the same pins UART0's
// debug console uses — the point being that this drives them through the
// separate AUX mini-UART instead, which is what a serial console has to
// fall back to once UART0 (PL011) is committed to something else (e.g.
// Bluetooth on the on-board wireless chip).
//
// The mini UART is clocked from the (dynamically scaled) VPU/core clock,
// so if the terminal shows garbage, pin the clock by adding `core_freq=250`
// to config.txt and rebooting. `enable_uart=1` alone is not enough when
// PL011 is the primary UART — see `rpi_hal::mini_uart::CORE_CLOCK_HZ`.
use core::fmt::Write;
use embedded_hal::digital::StatefulOutputPin;
use rpi_hal::gpio::{Input, Pin};
use rpi_hal::halt;
use rpi_hal::mini_uart::MiniUart;
use rpi_hal::pac;
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = MiniUart::init(&peripherals.GPIO, &peripherals.AUX, peripherals.UART1);
let _ = writeln!(uart, "PANIC: {info}");
halt();
}
#[no_mangle]
pub extern "C" fn kmain() -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = MiniUart::init(&peripherals.GPIO, &peripherals.AUX, peripherals.UART1);
// LED heartbeat on GPIO4: toggles every loop iteration regardless of
// whether the UART message reaches a terminal, so the loop is visibly
// alive even with nothing attached.
let mut led = Pin::<4, Input>::new(peripherals.GPIO).into_output();
let mut count: u32 = 0;
loop {
let _ = writeln!(uart, "hello from rpi-hal mini UART ({count})");
count += 1;
let _ = led.toggle();
delay(10_000_000);
}
}
fn delay(cycles: u32) {
for _ in 0..cycles {
unsafe { core::arch::asm!("nop") };
}
}