From 088dc691adac95bcbd95d32325b545e94d592566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Sat, 19 Oct 2024 11:28:51 +0200 Subject: [PATCH] Add new examples. Fix GPIO --- .cargo/config.toml | 5 +- e310x-hal/CHANGELOG.md | 3 ++ e310x-hal/src/gpio.rs | 25 ++++++---- hifive1-examples/.cargo/config.toml | 11 +++++ hifive1-examples/Cargo.toml | 35 ++++++++++++++ .../examples/hello_world.rs | 15 +++--- hifive1-examples/examples/led_blink.rs | 46 +++++++++++++++++++ .../examples/rgb_blink.rs | 17 +++++-- hifive1-examples/examples/sh_hello_world.rs | 12 +++++ .../examples/sh_led_blink.rs | 11 +++-- hifive1-examples/examples/sh_rgb_blink.rs | 46 +++++++++++++++++++ hifive1-examples/gdb_init | 12 +++++ hifive1-examples/gdb_init_sh | 13 ++++++ hifive1-examples/openocd.sh | 33 +++++++++++++ hifive1-examples/src/main.rs | 43 +++++++++++++++++ hifive1/Cargo.toml | 14 +----- 16 files changed, 300 insertions(+), 41 deletions(-) create mode 100644 hifive1-examples/.cargo/config.toml create mode 100644 hifive1-examples/Cargo.toml rename {hifive1 => hifive1-examples}/examples/hello_world.rs (63%) create mode 100644 hifive1-examples/examples/led_blink.rs rename {hifive1 => hifive1-examples}/examples/rgb_blink.rs (78%) create mode 100644 hifive1-examples/examples/sh_hello_world.rs rename hifive1/examples/led_blink.rs => hifive1-examples/examples/sh_led_blink.rs (79%) create mode 100644 hifive1-examples/examples/sh_rgb_blink.rs create mode 100644 hifive1-examples/gdb_init create mode 100644 hifive1-examples/gdb_init_sh create mode 100755 hifive1-examples/openocd.sh create mode 100644 hifive1-examples/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 96e920c..f1b92a1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,9 @@ [target.'cfg(all(target_arch = "riscv32", target_os = "none"))'] runner = "qemu-system-riscv32 -machine sifive_e,revb=true -nographic -semihosting-config enable=on,target=native -kernel" # Uncomment for QEMU -# runner = "riscv64-unknown-elf-gdb -q -x gdb_init" # Uncomment for hardware +# runner = "riscv64-unknown-elf-gdb -q -x hifive1-examples/gdb_init" # Uncomment for hardware (no semihosting) +# runner = "riscv64-unknown-elf-gdb -q -x hifive1-examples/gdb_init_sh" # Uncomment for hardware (semihosting) rustflags = [ - "-C", "link-arg=-Thifive1-link.x", + # "-C", "link-arg=-Thifive1-link.x", "--cfg", "portable_atomic_target_feature=\"zaamo\"", ] diff --git a/e310x-hal/CHANGELOG.md b/e310x-hal/CHANGELOG.md index 23e3be0..67f06a1 100644 --- a/e310x-hal/CHANGELOG.md +++ b/e310x-hal/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed +- Fix `StatefulOutputPin::is_set_high`. It now reads from `output_val` +- UART traits are implemented now from `embedded-hal-nb` 1.0.0 +- Update `embedded-hal` to 1.0.0 - Update `riscv` to 0.11.1 - Apply clippy changes - Use `portable-atomic` with `zaamo` feature to use native `amo*` operations. diff --git a/e310x-hal/src/gpio.rs b/e310x-hal/src/gpio.rs index 9a54aa4..db94e90 100644 --- a/e310x-hal/src/gpio.rs +++ b/e310x-hal/src/gpio.rs @@ -80,56 +80,61 @@ trait PeripheralAccess { fn set_input_en(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.input_en()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.input_en()) }; atomic_set_bit(r, index, bit); } fn set_output_en(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.output_en()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_en()) }; atomic_set_bit(r, index, bit); } + fn output_value(index: usize) -> bool { + let p = Self::peripheral(); + ((p.output_val().read().bits() >> (index & 31)) & 1) != 0 + } + fn set_output_value(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.output_val()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_val()) }; atomic_set_bit(r, index, bit); } fn toggle_pin(index: usize) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.output_val()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_val()) }; let mask = 1 << (index & 31); r.fetch_xor(mask, Ordering::SeqCst); } fn set_pullup(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.pullup()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.pullup()) }; atomic_set_bit(r, index, bit); } fn set_drive(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.drive()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.drive()) }; atomic_set_bit(r, index, bit); } fn set_out_xor(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.out_xor()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.out_xor()) }; atomic_set_bit(r, index, bit); } fn set_iof_en(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.iof_en()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.iof_en()) }; atomic_set_bit(r, index, bit); } fn set_iof_sel(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.iof_sel()) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(p.iof_sel()) }; atomic_set_bit(r, index, bit); } } @@ -310,7 +315,7 @@ macro_rules! gpio { impl StatefulOutputPin for $PXi> { #[inline] fn is_set_high(&mut self) -> Result { - Ok($GPIOX::input_value(Self::INDEX)) + Ok($GPIOX::output_value(Self::INDEX)) } #[inline] diff --git a/hifive1-examples/.cargo/config.toml b/hifive1-examples/.cargo/config.toml new file mode 100644 index 0000000..b634cbd --- /dev/null +++ b/hifive1-examples/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.'cfg(all(target_arch = "riscv32", target_os = "none"))'] +runner = "qemu-system-riscv32 -machine sifive_e,revb=true -nographic -semihosting-config enable=on,target=native -kernel" # Uncomment for QEMU +# runner = "riscv64-unknown-elf-gdb -q -x hifive1-examples/gdb_init" # Uncomment for hardware (no semihosting) +# runner = "riscv64-unknown-elf-gdb -q -x hifive1-examples/gdb_init_sh" # Uncomment for hardware (semihosting) +rustflags = [ + "-C", "link-arg=-Thifive1-link.x", + "--cfg", "portable_atomic_target_feature=\"zaamo\"", +] + +[build] +target = "riscv32imc-unknown-none-elf" diff --git a/hifive1-examples/Cargo.toml b/hifive1-examples/Cargo.toml new file mode 100644 index 0000000..19e653e --- /dev/null +++ b/hifive1-examples/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "hifive1-examples" +version = "0.1.0" +repository = "https://github.com/riscv-rust/e310x" +authors = ["David Craven "] +categories = ["embedded", "hardware-support", "no-std"] +description = "Running examples for HiFive1 and LoFive boards" +keywords = ["riscv", "register", "peripheral"] +license = "ISC" +edition = "2021" +rust-version = "1.72" + +[workspace] + +[dependencies] +critical-section = { version = "1.1.3" } +hifive1 = { path = "../hifive1", version = "0.13.0", features = ["board-hifive1-revb"] } # Change to your board +riscv-rt = { version = "0.12.2", features = ["single-hart"] } +panic-halt = "0.2.0" +semihosting = { version = "0.1", features = ["stdio", "panic-handler"], optional = true } + +[features] +virq = ["hifive1/virq"] + +[[example]] +name = "sh_hello_world" +required-features = ["semihosting"] + +[[example]] +name = "sh_led_blink" +required-features = ["semihosting"] + +[[example]] +name = "sh_rgb_blink" +required-features = ["semihosting"] diff --git a/hifive1/examples/hello_world.rs b/hifive1-examples/examples/hello_world.rs similarity index 63% rename from hifive1/examples/hello_world.rs rename to hifive1-examples/examples/hello_world.rs index 0064f66..5d4e1a4 100644 --- a/hifive1/examples/hello_world.rs +++ b/hifive1-examples/examples/hello_world.rs @@ -1,13 +1,16 @@ -//! Prints "hello world!" to the host console using semihosting and the on-board UART. +//! Prints "hello world!" to the host console. +//! +//! If "semihosting" feature is enabled, the message is printed using semihosting. +//! Otherwise, the message is printed using the UART0 peripheral. #![no_std] #![no_main] +extern crate panic_halt; use hifive1::{ hal::{prelude::*, DeviceResources}, - pin, sprintln, + pin, sprintln as println, }; -use semihosting::{println, process::exit}; #[riscv_rt::entry] fn main() -> ! { @@ -27,8 +30,6 @@ fn main() -> ! { clocks, ); - sprintln!("STDOUT: hello world!"); - println!("Semihosting: hello world!"); - - exit(0); + println!("Hello, world!"); + loop {} } diff --git a/hifive1-examples/examples/led_blink.rs b/hifive1-examples/examples/led_blink.rs new file mode 100644 index 0000000..40ee8de --- /dev/null +++ b/hifive1-examples/examples/led_blink.rs @@ -0,0 +1,46 @@ +//! Basic blinking LEDs example using mtime/mtimecmp registers for "sleep" in a loop. +//! Blinks each led once and goes to the next one. + +#![no_std] +#![no_main] + +use hifive1::{ + clock, + hal::{delay::Sleep, prelude::*, DeviceResources}, + pin, sprintln, Led, +}; +extern crate panic_halt; + +#[riscv_rt::entry] +fn main() -> ! { + let dr = DeviceResources::take().unwrap(); + let p = dr.peripherals; + let pins = dr.pins; + + // Configure clocks + let clocks = clock::configure(p.PRCI, p.AONCLK, 320.mhz().into()); + + // Configure UART for stdout + hifive1::stdout::configure( + p.UART0, + pin!(pins, uart0_tx), + pin!(pins, uart0_rx), + 115_200.bps(), + clocks, + ); + + // get all 3 led pins in a tuple (each pin is it's own type here) + let pin = pin!(pins, led_blue); + let mut led = pin.into_inverted_output(); + + // Get the sleep struct from CLINT + let clint = dr.core_peripherals.clint; + let mut sleep = Sleep::new(clint.mtimecmp, clocks); + + const STEP: u32 = 1000; // 1s + loop { + Led::toggle(&mut led); + sprintln!("LED toggled. New state: {}", led.is_on()); + sleep.delay_ms(STEP); + } +} diff --git a/hifive1/examples/rgb_blink.rs b/hifive1-examples/examples/rgb_blink.rs similarity index 78% rename from hifive1/examples/rgb_blink.rs rename to hifive1-examples/examples/rgb_blink.rs index eb151d0..dcc938d 100644 --- a/hifive1/examples/rgb_blink.rs +++ b/hifive1-examples/examples/rgb_blink.rs @@ -7,9 +7,9 @@ use hifive1::{ clock, hal::{delay::Sleep, prelude::*, DeviceResources}, - pins, Led, + pin, pins, sprintln, Led, }; -use semihosting::println; +extern crate panic_halt; #[riscv_rt::entry] fn main() -> ! { @@ -20,6 +20,15 @@ fn main() -> ! { // Configure clocks let clocks = clock::configure(p.PRCI, p.AONCLK, 320.mhz().into()); + // Configure UART for stdout + hifive1::stdout::configure( + p.UART0, + pin!(pins, uart0_tx), + pin!(pins, uart0_rx), + 115_200.bps(), + clocks, + ); + // get all 3 led pins in a tuple (each pin is it's own type here) let rgb_pins = pins!(pins, (led_red, led_green, led_blue)); let mut tleds = hifive1::rgb(rgb_pins.0, rgb_pins.1, rgb_pins.2); @@ -30,13 +39,11 @@ fn main() -> ! { let clint = dr.core_peripherals.clint; let mut sleep = Sleep::new(clint.mtimecmp, clocks); - println!("Starting blink loop"); - const STEP: u32 = 1000; // 1s loop { for (i, led) in ileds.iter_mut().enumerate() { led.toggle().unwrap(); - println!("LED {i} toggled. New state: {}", led.is_on()); + sprintln!("LED {} toggled. New state: {}", i, led.is_on()); sleep.delay_ms(STEP); } } diff --git a/hifive1-examples/examples/sh_hello_world.rs b/hifive1-examples/examples/sh_hello_world.rs new file mode 100644 index 0000000..50e3a08 --- /dev/null +++ b/hifive1-examples/examples/sh_hello_world.rs @@ -0,0 +1,12 @@ +//! Prints "hello world!" to the host console using semihosting. + +#![no_std] +#![no_main] + +use semihosting::{println, process::exit}; + +#[riscv_rt::entry] +fn main() -> ! { + println!("Hello, world!"); + exit(0); +} diff --git a/hifive1/examples/led_blink.rs b/hifive1-examples/examples/sh_led_blink.rs similarity index 79% rename from hifive1/examples/led_blink.rs rename to hifive1-examples/examples/sh_led_blink.rs index 36ec1c2..5f40957 100644 --- a/hifive1/examples/led_blink.rs +++ b/hifive1-examples/examples/sh_led_blink.rs @@ -9,7 +9,7 @@ use hifive1::{ hal::{delay::Sleep, prelude::*, DeviceResources}, pin, Led, }; -use semihosting::println; +use semihosting::{println, process::exit}; #[riscv_rt::entry] fn main() -> ! { @@ -28,12 +28,15 @@ fn main() -> ! { let clint = dr.core_peripherals.clint; let mut sleep = Sleep::new(clint.mtimecmp, clocks); - println!("Starting blink loop"); + const N_TOGGLE: usize = 4; + const STEP: u32 = 500; // 500 ms - const STEP: u32 = 1000; // 1s - loop { + println!("Toggling LED {} times", N_TOGGLE); + for _ in 0..N_TOGGLE { Led::toggle(&mut led); println!("LED toggled. New state: {}", led.is_on()); sleep.delay_ms(STEP); } + println!("Done toggling LED"); + exit(0); } diff --git a/hifive1-examples/examples/sh_rgb_blink.rs b/hifive1-examples/examples/sh_rgb_blink.rs new file mode 100644 index 0000000..8532840 --- /dev/null +++ b/hifive1-examples/examples/sh_rgb_blink.rs @@ -0,0 +1,46 @@ +//! Basic blinking LEDs example using mtime/mtimecmp registers for "sleep" in a loop. +//! Blinks each led once and goes to the next one. + +#![no_std] +#![no_main] + +use hifive1::{ + clock, + hal::{delay::Sleep, prelude::*, DeviceResources}, + pins, Led, +}; +use semihosting::{println, process::exit}; + +#[riscv_rt::entry] +fn main() -> ! { + let dr = DeviceResources::take().unwrap(); + let p = dr.peripherals; + let pins = dr.pins; + + // Configure clocks + let clocks = clock::configure(p.PRCI, p.AONCLK, 320.mhz().into()); + + // get all 3 led pins in a tuple (each pin is it's own type here) + let rgb_pins = pins!(pins, (led_red, led_green, led_blue)); + let mut tleds = hifive1::rgb(rgb_pins.0, rgb_pins.1, rgb_pins.2); + // get leds as the Led trait in an array so we can index them + let mut ileds: [&mut dyn Led; 3] = [&mut tleds.0, &mut tleds.1, &mut tleds.2]; + + // Get the sleep struct from CLINT + let clint = dr.core_peripherals.clint; + let mut sleep = Sleep::new(clint.mtimecmp, clocks); + + const N_TOGGLES: usize = 4; + const STEP: u32 = 500; // 500ms + + println!("Toggling LEDs {} times", N_TOGGLES); + for _ in 0..N_TOGGLES { + for (i, led) in ileds.iter_mut().enumerate() { + led.toggle().unwrap(); + println!("LED {i} toggled. New state: {}", led.is_on()); + sleep.delay_ms(STEP); + } + } + println!("Done toggling LEDs"); + exit(0); +} diff --git a/hifive1-examples/gdb_init b/hifive1-examples/gdb_init new file mode 100644 index 0000000..8719bc8 --- /dev/null +++ b/hifive1-examples/gdb_init @@ -0,0 +1,12 @@ +# GDB init file for HiFive1 boards + +# set history save on # uncomment to save history +set confirm off +set remotetimeout 240 +set print asm-demangle on + +target extended-remote :3333 +monitor reset halt +load +continue # uncomment to start running after loading +# quit # uncomment to exit after loading diff --git a/hifive1-examples/gdb_init_sh b/hifive1-examples/gdb_init_sh new file mode 100644 index 0000000..925f2f9 --- /dev/null +++ b/hifive1-examples/gdb_init_sh @@ -0,0 +1,13 @@ +# GDB init file for HiFive1 boards (including semihosting) + +# set history save on # uncomment to save history +set confirm off +set remotetimeout 240 +set print asm-demangle on + +target extended-remote :3333 +monitor reset halt +monitor arm semihosting enable +load +continue # uncomment to start running after loading +# quit # uncomment to exit after loading diff --git a/hifive1-examples/openocd.sh b/hifive1-examples/openocd.sh new file mode 100755 index 0000000..2587073 --- /dev/null +++ b/hifive1-examples/openocd.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# This script runs OpenOCD with the specified configuration file +# for the HiFive1 board. The configuration file is selected based +# on the revb argument, which is a boolean flag that indicates +# whether the HiFive1 Rev B board is being used. If the revb +# argument is not provided, the default configuration file for +# the HiFive1 Rev A board is used. + +# Default path to OpenOCD +OPENOCD_PATH="openocd" +REVB=false + +# Parse command-line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + -p|--path) OPENOCD_PATH="$2"; shift ;; + revb) REVB=true ;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +# Determine the configuration file based on the revb argument +if [ "$REVB" = true ]; then + CONFIG_FILE="sifive-hifive1-revb.cfg" +else + CONFIG_FILE="sifive-hifive1.cfg" +fi + +# Run OpenOCD with the specified configuration file +echo "Running $OPENOCD_PATH -f board/$CONFIG_FILE" +$OPENOCD_PATH -f board/$CONFIG_FILE diff --git a/hifive1-examples/src/main.rs b/hifive1-examples/src/main.rs new file mode 100644 index 0000000..176b305 --- /dev/null +++ b/hifive1-examples/src/main.rs @@ -0,0 +1,43 @@ +//! Prints "hello world!" to the host console using the on-board UART. +//! +//! # Note +//! +//! We have noticed that using the UART while debugging with GDB can cause +//! the GDB session to hang. Thus, you will probably want to run this example +//! without GDB. Otherwise, you might not be able to see the output. + +#![no_std] +#![no_main] + +use hifive1::{ + hal::{prelude::*, DeviceResources}, + pin, sprintln, +}; + +#[cfg(not(feature = "semihosting"))] +extern crate panic_halt; +#[cfg(feature = "semihosting")] +extern crate semihosting; + +#[riscv_rt::entry] +fn main() -> ! { + let dr = DeviceResources::take().unwrap(); + let p = dr.peripherals; + let pins = dr.pins; + + // Configure clocks + let clocks = hifive1::clock::configure(p.PRCI, p.AONCLK, 320.mhz().into()); + + // Configure UART for stdout + hifive1::stdout::configure( + p.UART0, + pin!(pins, uart0_tx), + pin!(pins, uart0_rx), + 115_200.bps(), + clocks, + ); + + sprintln!("Hello, world!"); + + loop {} +} diff --git a/hifive1/Cargo.toml b/hifive1/Cargo.toml index 8011c8e..c88ca2f 100644 --- a/hifive1/Cargo.toml +++ b/hifive1/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hifive1" version = "0.13.0" -repository = "https://github.com/riscv-rust/hifive1" +repository = "https://github.com/riscv-rust/e310x" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] description = "Board support crate for HiFive1 and LoFive boards" @@ -16,10 +16,6 @@ e310x-hal = { path = "../e310x-hal", version = "0.11.0" } nb = "1.0.0" riscv = "0.11.1" -[dev-dependencies] -riscv-rt = { version = "0.12.2", features = ["single-hart"] } -semihosting = { version = "0.1", features = ["stdio", "panic-handler"] } - [features] board-hifive1 = [] board-hifive1-revb = ["e310x-hal/g002"] @@ -30,11 +26,3 @@ virq = ["e310x-hal/virq"] [package.metadata.docs.rs] features = ['board-hifive1-revb'] - -[[example]] -name = "led_blink" -required-features = ["board-hifive1-revb"] - -[[example]] -name = "rgb_blink" -required-features = ["board-hifive1-revb"]