Выбрать главу

Let's see an example:

#![no_std]

#![no_main]

use panic_halt as _; // panic handler

use cortex_m_rt::entry;

use tm4c123x_hal as hal;

use tm4c123x_haclass="underline" :prelude::*;

use tm4c123x_haclass="underline" :seriaclass="underline" :{NewlineMode, Serial};

use tm4c123x_haclass="underline" :sysctl;

#[entry]

fn main() -> ! {

let p = haclass="underline" :Peripherals::take().unwrap();

let cp = haclass="underline" :CorePeripherals::take().unwrap();

// Wrap up the SYSCTL struct into an object with a higher-layer API

let mut sc = p.SYSCTL.constrain();

// Pick our oscillation settings

sc.clock_setup.oscillator = sysctclass="underline" :Oscillator::Main(

sysctclass="underline" :CrystalFrequency::_16mhz,

sysctclass="underline" :SystemClock::UsePll(sysctclass="underline" :PllOutputFrequency::_80_00mhz),

);

// Configure the PLL with those settings

let clocks = sc.clock_setup.freeze();

// Wrap up the GPIO_PORTA struct into an object with a higher-layer API.

// Note it needs to borrow `sc.power_control` so it can power up the GPIO

// peripheral automatically.

let mut porta = p.GPIO_PORTA.split(&sc.power_control);

// Activate the UART.

let uart = Seriaclass="underline" :uart0(

p.UART0,

// The transmit pin

porta

.pa1

.into_af_push_pulclass="underline" :<haclass="underline" :gpio::AF1>(&mut porta.control),

// The receive pin

porta

.pa0

.into_af_push_pulclass="underline" :<haclass="underline" :gpio::AF1>(&mut porta.control),

// No RTS or CTS required

(),

(),

// The baud rate

115200_u32.bps(),

// Output handling

NewlineMode::SwapLFtoCRLF,

// We need the clock rates to calculate the baud rate divisors

&clocks,

// We need this to power up the UART peripheral

&sc.power_control,

);

loop {

writeln!(uart, "Hello, World!\r\n").unwrap();

}

}

Semihosting is a mechanism that lets embedded devices do I/O on the host and is mainly used to log messages to the host console. Semihosting requires a debug session and pretty much nothing else (no extra wires!) so it's super convenient to use. The downside is that it's super slow: each write operation can take several milliseconds depending on the hardware debugger (e.g. ST-Link) you use.

The cortex-m-semihosting crate provides an API to do semihosting operations on Cortex-M devices. The program below is the semihosting version of "Hello, world!":

#![no_main]

#![no_std]

use panic_halt as _;

use cortex_m_rt::entry;

use cortex_m_semihosting::hprintln;

#[entry]

fn main() -> ! {

hprintln!("Hello, world!").unwrap();

loop {}

}

If you run this program on hardware you'll see the "Hello, world!" message within the OpenOCD logs.

$ openocd

(..)

Hello, world!

(..)

You do need to enable semihosting in OpenOCD from GDB first:

(gdb) monitor arm semihosting enable

semihosting is enabled

QEMU understands semihosting operations so the above program will also work with qemu-system-arm without having to start a debug session. Note that you'll need to pass the -semihosting-config flag to QEMU to enable semihosting support; these flags are already included in the .cargo/config.toml file of the template.

$ # this program will block the terminal

$ cargo run

Running `qemu-system-arm (..)

Hello, world!

There's also an exit semihosting operation that can be used to terminate the QEMU process. Important: do not use debug::exit on hardware; this function can corrupt your OpenOCD session and you will not be able to debug more programs until you restart it.

#![no_main]

#![no_std]

use panic_halt as _;

use cortex_m_rt::entry;

use cortex_m_semihosting::debug;

#[entry]

fn main() -> ! {

let roses = "blue";

if roses == "red" {

debug::exit(debug::EXIT_SUCCESS);

} else {

debug::exit(debug::EXIT_FAILURE);

}

loop {}

}

$ cargo run

Running `qemu-system-arm (..)

$ echo $?

1

One last tip: you can set the panicking behavior to exit(EXIT_FAILURE). This will let you write no_std run-pass tests that you can run on QEMU.

For convenience, the panic-semihosting crate has an "exit" feature that when enabled invokes exit(EXIT_FAILURE) after logging the panic message to the host stderr.

#![no_main]

#![no_std]

use panic_semihosting as _; // features = ["exit"]

use cortex_m_rt::entry;

use cortex_m_semihosting::debug;

#[entry]

fn main() -> ! {

let roses = "blue";

assert_eq!(roses, "red");

loop {}

}

$ cargo run

Running `qemu-system-arm (..)

panicked at 'assertion failed: `(left == right)`

left: `"blue"`,

right: `"red"`', examples/hello.rs:15:5