From 8d4ba623c350462ccf3fb838f87d62e1abb44327 Mon Sep 17 00:00:00 2001 From: David Craven Date: Mon, 20 Nov 2017 08:03:09 +0100 Subject: [PATCH 001/315] Initial commit. --- .cargo/config | 6 + .gdbinit | 24 ++ .gitignore | 4 + Cargo.toml | 30 +++ Makefile | 51 ++++ README.md | 18 ++ Xargo.toml | 7 + build.rs | 24 ++ examples/blinky_clint.rs | 20 ++ examples/blinky_delay.rs | 34 +++ examples/blinky_plic.rs | 43 ++++ examples/blinky_pwm.rs | 81 ++++++ examples/hello_world.rs | 13 + examples/panicking.rs | 20 ++ memory.x | 22 ++ openocd.cfg | 34 +++ src/clint.rs | 156 ++++++++++++ src/clock.rs | 120 +++++++++ src/gpio.rs | 204 ++++++++++++++++ src/led.rs | 42 ++++ src/lib.rs | 225 +++++++++++++++++ src/plic.rs | 125 ++++++++++ src/pwm.rs | 515 +++++++++++++++++++++++++++++++++++++++ src/serial.rs | 151 ++++++++++++ src/time.rs | 110 +++++++++ 25 files changed, 2079 insertions(+) create mode 100644 .cargo/config create mode 100644 .gdbinit create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 Makefile create mode 100644 README.md create mode 100644 Xargo.toml create mode 100644 build.rs create mode 100644 examples/blinky_clint.rs create mode 100644 examples/blinky_delay.rs create mode 100644 examples/blinky_plic.rs create mode 100644 examples/blinky_pwm.rs create mode 100644 examples/hello_world.rs create mode 100644 examples/panicking.rs create mode 100644 memory.x create mode 100644 openocd.cfg create mode 100644 src/clint.rs create mode 100644 src/clock.rs create mode 100644 src/gpio.rs create mode 100644 src/led.rs create mode 100644 src/lib.rs create mode 100644 src/plic.rs create mode 100644 src/pwm.rs create mode 100644 src/serial.rs create mode 100644 src/time.rs diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..a4229f7 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,6 @@ +[target.riscv32-unknown-none] +runner = 'riscv32-unknown-elf-gdb' +rustflags = [ + "-C", "link-arg=-Tlink.x", + "-C", "linker=riscv32-unknown-elf-ld", +] \ No newline at end of file diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..b99fc56 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,24 @@ +set remotetimeout 240 +target extended-remote localhost:3333 + +define upload + monitor reset halt + monitor flash protect 0 64 last off + load + monitor flash protect 0 64 last on + continue +end +document upload +Upload program to hifive board +end + +# Load Rust's GDB pretty printers +python +import os; +import sys; +path = os.environ['TOOLCHAIN'] + '/lib/rustlib/etc' +sys.path.append(path) + +gdb.execute('directory %s' % path) +gdb.execute('add-auto-load-safe-path %s' % path) +end diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..becb52e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +Cargo.lock +target/ +core +.gdb_history \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..acabf39 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "hifive" +version = "0.1.0" +repository = "https://github.com/dvc94ch/hifive" +authors = ["David Craven "] +categories = ["embedded", "hardware-support", "no-std"] +description = "Board support crate for hifive and lofive boards." +keywords = ["riscv", "register", "peripheral"] +license = "ISC" + +[dependencies.embedded-hal] +git = "https://github.com/japaric/embedded-hal" +rev = "7d904f515d15fd5fe7ea34e18820ea83e2651fa2" + +[dependencies.nb] +git = "https://github.com/japaric/nb" + +[dependencies.e310x] +features = ["rt"] +version = "^0.1.1" + +[dependencies.riscv] +version = "^0.1.3" + +[dev-dependencies.riscv-rt] +version = "^0.1.3" + +[profile.release] +debug = true +lto = true \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0ce4811 --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +# Examples (uncomment one) +EXAMPLE := blinky_delay +#EXAMPLE := blinky_clint +#EXAMPLE := blinky_pwm +#EXAMPLE := blinky_plic +#EXAMPLE := hello_world +#EXAMPLE := panicking +#EXAMPLE := heaps +#EXAMPLE := rtc +#EXAMPLE := watchdog +#EXAMPLE := utest +#EXAMPLE := rtfm + +# Board crate (uncomment one) +BOARD := hifive + +TARGET := riscv32-unknown-none +TARGET_DIR := $(abspath ./target/$(TARGET)/debug) +EXAMPLE_BIN := $(TARGET_DIR)/examples/$(EXAMPLE) +OPENOCD_CFG := $(wildcard $(TARGET_DIR)/build/$(BOARD)-*/out/openocd.cfg) + +build: + xargo build --examples --target $(TARGET) $(ARGS) + +test: + xargo test --all --target $(TARGET) $(ARGS) + +clean: + xargo clean $(ARGS) + +readelf: + llvm-readelf -a -h -s -r -symbols $(EXAMPLE_BIN) $(ARGS) + +objdump: + llvm-objdump -d -S $(EXAMPLE_BIN) $(ARGS) + +size: + llvm-size $(EXAMPLE_BIN) $(ARGS) + +# .gdbinit adds a upload command to gdb +gdb: + riscv32-unknown-elf-gdb $(EXAMPLE_BIN) $(ARGS) + +openocd: + openocd -f $(OPENOCD_CFG) $(ARGS) + +upload: + openocd -f $(OPENOCD_CFG) \ + -c "flash protect 0 64 last off; program ${EXAMPLE_BIN}; resume 0x20400000; exit" + +.PHONY: build clean readelf objdump framedump size gdb openocd spike diff --git a/README.md b/README.md new file mode 100644 index 0000000..46f873d --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# `hifive` + +> Board support crate for hifive and lofive boards. + +# License +Copyright 2017 David Craven + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 0000000..001a159 --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,7 @@ +[dependencies] +core = {} +alloc = {} + +[dependencies.compiler_builtins] +features = ["mem"] +stage = 1 diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..ab3a5b6 --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put the linker script somewhere the linker can find it + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); + + // Copy openocd.cfg to output directory + File::create(out.join("openocd.cfg")) + .unwrap() + .write_all(include_bytes!("openocd.cfg")) + .unwrap(); + println!("cargo:rerun-if-changed=openocd.cfg"); + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/examples/blinky_clint.rs b/examples/blinky_clint.rs new file mode 100644 index 0000000..f96cfdc --- /dev/null +++ b/examples/blinky_clint.rs @@ -0,0 +1,20 @@ +#![no_std] + +extern crate hifive; + +use hifive::prelude::*; +use hifive::{led, Blue, Clint, Peripherals, UExt}; + +fn main() { + let peripherals = hifive::init(115_200); + led::init(peripherals.GPIO0); + + let timer = Clint(peripherals.CLINT); + timer.set_timeout(1.s()); +} + +#[no_mangle] +pub fn mtimer_trap_handler(p: &Peripherals) { + Clint(p.CLINT).restart(); + Blue::toggle(p.GPIO0); +} diff --git a/examples/blinky_delay.rs b/examples/blinky_delay.rs new file mode 100644 index 0000000..3f40f33 --- /dev/null +++ b/examples/blinky_delay.rs @@ -0,0 +1,34 @@ +#![no_std] + +#[macro_use] +extern crate nb; +extern crate hifive; + +use hifive::prelude::*; +use hifive::{led, Red, Green, Blue, Clint, UExt}; + +fn delay(clint: &Clint) { + block!(clint.wait()).unwrap(); + clint.restart(); +} + +fn main() { + let peripherals = hifive::init(115_200); + led::init(peripherals.GPIO0); + + let clint = Clint(peripherals.CLINT); + clint.set_timeout(500.ms()); + + let gpio = peripherals.GPIO0; + loop { + Red::on(gpio); + delay(&clint); + Red::off(gpio); + Green::on(gpio); + delay(&clint); + Green::off(gpio); + Blue::on(gpio); + delay(&clint); + Blue::off(gpio); + } +} diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs new file mode 100644 index 0000000..86c92e5 --- /dev/null +++ b/examples/blinky_plic.rs @@ -0,0 +1,43 @@ +#![no_std] + +extern crate hifive; + +use hifive::{led, Red, Blue, Green, Interrupt, Plic, Channel, Pwm, Peripherals}; + +fn main() { + let peripherals = hifive::init(115_200); + led::init(peripherals.GPIO0); + + let pwm = Pwm(peripherals.PWM0); + pwm.init(); + pwm.set_cmp(Channel::_0, u16::max_value()); + pwm.set_cmp(Channel::_1, 0); + pwm.set_cmp(Channel::_2, u16::max_value() / 2); + + let plic = Plic(peripherals.PLIC); + plic.enable(Interrupt::PWM0CMP0); + plic.enable(Interrupt::PWM0CMP1); + plic.enable(Interrupt::PWM0CMP2); + plic.enable(Interrupt::PWM0CMP3); +} + +#[no_mangle] +pub fn plic_trap_handler(p: &Peripherals, intr: &Interrupt) { + //let pwm = Pwm(p.PWM0); + + match *intr { + Interrupt::PWM0CMP0 => { + Blue::toggle(p.GPIO0); + }, + Interrupt::PWM0CMP1 => { + Green::toggle(p.GPIO0); + }, + Interrupt::PWM0CMP2 => { + Red::toggle(p.GPIO0); + }, + Interrupt::PWM0CMP3 => { + + }, + _ => {}, + } +} diff --git a/examples/blinky_pwm.rs b/examples/blinky_pwm.rs new file mode 100644 index 0000000..bf0d14a --- /dev/null +++ b/examples/blinky_pwm.rs @@ -0,0 +1,81 @@ +#![no_std] + +extern crate hifive; + +use hifive::{Channel, Align, Pwm}; + +const RED: Channel = Channel::_3; +const GREEN: Channel = Channel::_1; +const BLUE: Channel = Channel::_2; + +/* +struct Color { + red: u8, + green: u8, + blue: u8, +} + +impl Color { + pub fn from(red: u8, green: u8, blue: u8) -> Self { + Color { red, green, blue } + } +} + +fn set_color(pwm: Pwm, color: Color) { + pwm.set_cmp(RED, u16::max_value() / 255 * color.red as u16); + pwm.set_cmp(GREEN, u16::max_value() / 255 * color.green as u16); + pwm.set_cmp(BLUE, u16::max_value() / 255 * color.blue as u16); +} +*/ + +fn main() { + let peripherals = hifive::init(115_200); + let gpio = peripherals.GPIO0; + + //let clint = Clint(peripherals.CLINT); + let pwm = Pwm(peripherals.PWM1); + + pwm.set_cmp(Channel::_0, u16::max_value()); + //pwm.set_period(63); + + pwm.enable(RED, Align::Left, gpio); + pwm.invert(RED, gpio); + pwm.set_cmp(RED, u16::max_value() / 3); + + pwm.enable(GREEN, Align::Center, gpio); + pwm.invert(GREEN, gpio); + pwm.set_cmp(GREEN, u16::max_value() / 2); + + pwm.enable(BLUE, Align::Right, gpio); + pwm.invert(BLUE, gpio); + pwm.set_cmp(BLUE, u16::max_value() / 3 * 2); + + pwm.init(); + + //let delay = 1.s(); + + /*loop { + // Gray + set_color(pwm, Color::from(0x80, 0x80, 0x80)); + clint.set_timeout(delay); + block!(clint.wait()); + // Purple + set_color(pwm, Color::from(0x80, 0x00, 0x80)); + clint.set_timeout(delay); + block!(clint.wait()); + // Maroon + set_color(pwm, Color::from(0x80, 0x00, 0x00)); + clint.set_timeout(delay); + block!(clint.wait()); + }*/ + + //pwm.invert(GREEN, gpio, true); + //pwm.align_center(GREEN); + //pwm.set_cmp(GREEN, u16::max_value() / 2); + + //pwm.align_left(RED); + //pwm.align_right(BLUE); + //pwm.set_cmp(BLUE, u16::max_value() / 3 * 2); + //pwm.set_cmp(BLUE, 0); + //pwm.enable(BLUE, gpio); +} diff --git a/examples/hello_world.rs b/examples/hello_world.rs new file mode 100644 index 0000000..9f5678d --- /dev/null +++ b/examples/hello_world.rs @@ -0,0 +1,13 @@ +#![no_std] + +extern crate hifive; + +use core::fmt::Write; +use hifive::{Port, Serial}; + +fn main() { + let peripherals = hifive::init(115_200); + + let serial = Serial(peripherals.UART0); + writeln!(Port(&serial), "hello world!").unwrap(); +} diff --git a/examples/panicking.rs b/examples/panicking.rs new file mode 100644 index 0000000..5dba0f9 --- /dev/null +++ b/examples/panicking.rs @@ -0,0 +1,20 @@ +#![no_std] + +extern crate hifive; + +fn three() { + panic!() +} + +fn two() { + three(); +} + +fn one() { + two(); +} + +fn main() { + hifive::init(115_200); + one(); +} diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..c991460 --- /dev/null +++ b/memory.x @@ -0,0 +1,22 @@ +MEMORY +{ +/* NOTE K = KiBi = 1024 bytes */ +/* TODO Adjust these memory regions to match your device memory layout */ +FLASH : ORIGIN = 0x20400000, LENGTH = 512M +RAM : ORIGIN = 0x80000000, LENGTH = 16K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* You may want to use this variable to locate the call stack and static +variables in different memory regions. Below is shown the default value */ + +/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ + +/* You can use this symbol to customize the location of the .text section */ +/* If omitted the .text section will be placed right after the .vector_table +section */ +/* This is required only on microcontrollers that store some configuration right +after the vector table */ + +/* _stext = ORIGIN(FLASH); */ diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..40e7849 --- /dev/null +++ b/openocd.cfg @@ -0,0 +1,34 @@ +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Dual RS232-HS" +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 + +#Reset Stretcher logic on FE310 is ~1 second long +#This doesn't apply if you use +# ftdi_set_signal, but still good to document +#adapter_nsrst_delay 1500 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME +$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME +init +#reset -- This type of reset is not implemented yet +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z + #Wait for the reset stretcher + #It will work without this, but + #will incur lots of delays for later commands. + sleep 1500 +} +halt +#flash protect 0 64 last off \ No newline at end of file diff --git a/src/clint.rs b/src/clint.rs new file mode 100644 index 0000000..e0d905d --- /dev/null +++ b/src/clint.rs @@ -0,0 +1,156 @@ +//! Clint + +use riscv::{csr, interrupt}; +use e310x::CLINT; + +pub struct Clint<'a>(pub &'a CLINT); + +impl<'a> Clone for Clint<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Copy for Clint<'a> { +} + +impl<'a> Clint<'a> { + pub fn get_mtime(&self) -> ::aonclk::Ticks { + loop { + let hi = self.0.mtimeh.read().bits(); + let lo = self.0.mtime.read().bits(); + if hi == self.0.mtimeh.read().bits() { + return ::aonclk::Ticks(((hi as u64) << 32) | lo as u64); + } + } + } + + pub fn set_mtime(&self, time: ::aonclk::Ticks) { + unsafe { + self.0.mtimeh.write(|w| w.bits(time.into_hi())); + self.0.mtime.write(|w| w.bits(time.into())); + } + } + + pub fn get_mtimecmp(&self) -> ::aonclk::Ticks { + let hi = self.0.mtimecmph.read().bits() as u64; + let lo = self.0.mtimecmp.read().bits() as u64; + ::aonclk::Ticks(hi << 32 | lo) + } + + pub fn set_mtimecmp(&self, time: ::aonclk::Ticks) { + unsafe { + self.0.mtimecmph.write(|w| w.bits(time.into_hi())); + self.0.mtimecmp.write(|w| w.bits(time.into())); + } + } + + pub fn get_mcycle(&self) -> ::coreclk::Ticks { + loop { + let hi = csr::mcycleh.read().bits(); + let lo = csr::mcycle.read().bits(); + if hi == csr::mcycleh.read().bits() { + return ::coreclk::Ticks(((hi as u64) << 32) | lo as u64); + } + } + } + + pub fn set_mcycle(&self, cycle: ::coreclk::Ticks) { + csr::mcycleh.write(|w| w.bits(cycle.into_hi())); + csr::mcycle.write(|w| w.bits(cycle.into())); + } + + pub fn get_minstret(&self) -> u64 { + loop { + let hi = csr::minstreth.read().bits(); + let lo = csr::minstret.read().bits(); + if hi == csr::minstreth.read().bits() { + return ((hi as u64) << 32) | lo as u64; + } + } + } + + pub fn set_minstret(&self, instret: u64) { + csr::minstreth.write(|w| w.bits((instret >> 32) as u32)); + csr::minstret.write(|w| w.bits(instret as u32)); + } + + + /// Enable the Machine-Timer interrupt + pub fn enable_mtimer(&self) { + csr::mie.set(|w| w.mtimer()); + } + + /// Disable the Machine-Timer interrupt + pub fn disable_mtimer(&self) { + csr::mie.clear(|w| w.mtimer()); + } + + // Is Machine-Timer interrupt pending + pub fn is_mtimer_pending(&self) -> bool { + csr::mip.read().mtimer() + } + + pub fn measure_coreclk(&self, min_ticks: ::aonclk::Ticks) -> u32 { + interrupt::free(|_| { + let clint = self.0; + + // Don't start measuring until we see an mtime tick + while clint.mtime.read().bits() == clint.mtime.read().bits() {} + + let start_cycle = self.get_mcycle(); + let start_time = self.get_mtime(); + + // Wait for min_ticks to pass + while start_time + min_ticks > self.get_mtime() {} + + let end_cycle = self.get_mcycle(); + let end_time = self.get_mtime(); + + let delta_cycle: u32 = (end_cycle - start_cycle).into(); + let delta_time: u32 = (end_time - start_time).into(); + + (delta_cycle / delta_time) * 32768 + + ((delta_cycle % delta_time) * 32768) / delta_time + }) + } +} + +impl<'a> ::hal::Timer for Clint<'a> { + type Time = ::aonclk::Ticks; + + fn get_timeout(&self) -> ::aonclk::Ticks { + self.get_mtimecmp() + } + + fn pause(&self) { + self.disable_mtimer(); + } + + fn restart(&self) { + self.set_mtime(::aonclk::Ticks(0)); + self.enable_mtimer(); + } + + fn resume(&self) { + unimplemented!(); + } + + fn set_timeout(&self, timeout: T) + where + T: Into<::aonclk::Ticks>, + { + self.disable_mtimer(); + self.set_mtimecmp(timeout.into()); + self.set_mtime(::aonclk::Ticks(0)); + self.enable_mtimer(); + } + + fn wait(&self) -> ::nb::Result<(), !> { + if self.is_mtimer_pending() { + Ok(()) + } else { + Err(::nb::Error::WouldBlock) + } + } +} diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..46e36b6 --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,120 @@ +//! Clock configuration +use e310x::{AONCLK, prci, PRCI}; +use clint::Clint; + +/// Aon Clock interface +pub struct AonClock<'a>(pub &'a AONCLK); + +impl<'a> Clone for AonClock<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Copy for AonClock<'a> {} + +impl<'a> AonClock<'a> { + /// Use external real time oscillator + pub unsafe fn use_external(&self) { + // The G000 doesn't have a LFXOSC and is hardwired + // to use the an external oscillator. + // Disable unused LFROSC to save power. + self.0.lfrosccfg.write(|w| w.enable().bit(false)); + } +} + +/// Core Clock interface +pub struct CoreClock<'a>(pub &'a PRCI); + +impl<'a> Clone for CoreClock<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Copy for CoreClock<'a> { +} + +impl<'a> CoreClock<'a> { + pub unsafe fn use_external(&self, clint: &Clint) { + self.use_pll(clint, |_, w| { + // bypass PLL + w.bypass().bit(true) + // select HFXOSC + .refsel().bit(true) + }, |w| w.divby1().bit(true)); + } + + unsafe fn wait_for_lock(&self, clint: &Clint) { + // Won't lock when bypassed and will loop forever + if !self.0.pllcfg.read().bypass().bit_is_set() { + // Wait for PLL Lock + // Note that the Lock signal can be glitchy. + // Need to wait 100 us + // RTC is running at 32kHz. + // So wait 4 ticks of RTC. + let time = clint.get_mtime() + ::aonclk::Ticks(4); + while clint.get_mtime() < time {} + // Now it is safe to check for PLL Lock + while !self.0.pllcfg.read().lock().bit_is_set() {} + } + } + + pub unsafe fn use_pll(&self, clint: &Clint, pllcfg: F, plloutdiv: G) + where + for<'w> F: FnOnce(&prci::pllcfg::R, + &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, + for<'w> G: FnOnce(&'w mut prci::plloutdiv::W) -> &'w mut prci::plloutdiv::W, + { + // Make sure we are running of internal clock + // before configuring the PLL. + self.use_internal(); + // Enable HFXOSC + self.0.hfxosccfg.write(|w| w.enable().bit(true)); + // Wait for HFXOSC to stabilize + while !self.0.hfxosccfg.read().ready().bit_is_set() {} + // Configure PLL + self.0.pllcfg.modify(pllcfg); + self.0.plloutdiv.write(plloutdiv); + // Wait for PLL lock + self.wait_for_lock(clint); + // Switch to PLL + self.0.pllcfg.modify(|_, w| { + w.sel().bit(true) + }); + // Disable HFROSC to save power + self.0.hfrosccfg.write(|w| w.enable().bit(false)); + } + + pub unsafe fn use_internal(&self) { + // Enable HFROSC + self.0.hfrosccfg.write(|w| { + w.enable().bit(true) + // It is OK to change this even if we are running off of it. + // Reset them to default values. + .div().bits(4) + .trim().bits(16) + }); + // Wait for HFROSC to stabilize + while !self.0.hfrosccfg.read().ready().bit_is_set() {} + // Switch to HFROSC + self.0.pllcfg.modify(|_, w| { + w.sel().bit(false) + }); + // Bypass PLL to save power + self.0.pllcfg.modify(|_, w| { + w.bypass().bit(true) + // Select HFROSC as PLL ref to disable HFXOSC later + .refsel().bit(false) + }); + // Disable HFXOSC to save power. + self.0.hfxosccfg.write(|w| w.enable().bit(false)); + } + + pub fn measure(&self, clint: &Clint) -> u32 { + // warm up I$ + clint.measure_coreclk(::aonclk::Ticks(1)); + // measure for real + clint.measure_coreclk(::aonclk::Ticks(10)) + } +} diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..f5eb655 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,204 @@ +//! General Purpose I/O + +use core::ops::Deref; +use e310x::gpio0; + +pub enum PinConfig { + Input, + InputPullup, + Output, + OutputDrive, + IoFn0, + IoFn1, +} + +pub enum PinInterrupt { + Rise, + Fall, + High, + Low, +} + +macro_rules! pin { + ($Pin:ident, $pinx:ident) => ( + pub struct $Pin; + + impl $Pin { + pub fn init(gpio: &T, config: PinConfig) + where + T: Deref, + { + match config { + PinConfig::Input => { + gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); + gpio.pullup.modify(|_, w| w.$pinx().bit(false)); + gpio.input_en.modify(|_, w| w.$pinx().bit(true)); + }, + PinConfig::InputPullup => { + gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); + gpio.pullup.modify(|_, w| w.$pinx().bit(true)); + gpio.input_en.modify(|_, w| w.$pinx().bit(true)); + }, + PinConfig::Output => { + gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); + gpio.drive.modify(|_, w| w.$pinx().bit(false)); + gpio.output_en.modify(|_, w| w.$pinx().bit(true)); + }, + PinConfig::OutputDrive => { + gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); + gpio.drive.modify(|_, w| w.$pinx().bit(true)); + gpio.output_en.modify(|_, w| w.$pinx().bit(true)); + }, + PinConfig::IoFn0 => { + gpio.iof_sel.modify(|_, w| w.$pinx().bit(false)); + gpio.iof_en.modify(|_, w| w.$pinx().bit(true)); + }, + PinConfig::IoFn1 => { + gpio.iof_sel.modify(|_, w| w.$pinx().bit(true)); + gpio.iof_en.modify(|_, w| w.$pinx().bit(true)); + }, + } + } + + pub fn read(gpio: &T) -> bool + where + T: Deref, + { + gpio.value.read().$pinx().bit() + } + + pub fn write(gpio: &T, value: bool) + where + T: Deref, + { + match value { + true => $Pin::high(gpio), + false => $Pin::low(gpio), + } + } + + pub fn high(gpio: &T) + where + T: Deref, + { + gpio.port.modify(|_, w| w.$pinx().bit(true)); + } + + pub fn low(gpio: &T) + where + T: Deref, + { + gpio.port.modify(|_, w| w.$pinx().bit(false)); + } + + pub fn toggle(gpio: &T) + where + T: Deref, + { + gpio.port.modify(|r, w| w.$pinx().bit(!r.$pinx().bit())); + } + + pub fn enable_interrupt(gpio: &T, intr: PinInterrupt) + where + T: Deref, + { + match intr { + PinInterrupt::Rise => + gpio.rise_ie.modify(|_, w| w.$pinx().bit(true)), + PinInterrupt::Fall => + gpio.fall_ie.modify(|_, w| w.$pinx().bit(true)), + PinInterrupt::High => + gpio.high_ie.modify(|_, w| w.$pinx().bit(true)), + PinInterrupt::Low => + gpio.low_ie.modify(|_, w| w.$pinx().bit(true)), + }; + } + + pub fn disable_interrupt(gpio: &T, intr: PinInterrupt) + where + T: Deref, + { + match intr { + PinInterrupt::Rise => + gpio.rise_ie.modify(|_, w| w.$pinx().bit(false)), + PinInterrupt::Fall => + gpio.fall_ie.modify(|_, w| w.$pinx().bit(false)), + PinInterrupt::High => + gpio.high_ie.modify(|_, w| w.$pinx().bit(false)), + PinInterrupt::Low => + gpio.low_ie.modify(|_, w| w.$pinx().bit(false)), + }; + } + + pub fn is_interrupt_pending(gpio: &T, intr: PinInterrupt) -> bool + where + T: Deref, + { + match intr { + PinInterrupt::Rise => + gpio.rise_ip.read().$pinx().bit(), + PinInterrupt::Fall => + gpio.fall_ip.read().$pinx().bit(), + PinInterrupt::High => + gpio.high_ip.read().$pinx().bit(), + PinInterrupt::Low => + gpio.low_ip.read().$pinx().bit(), + } + } + + pub fn is_inverted(gpio: &T) -> bool + where + T: Deref, + { + gpio.out_xor.read().$pinx().bit() + } + + pub fn set_invert(gpio: &T, value: bool) + where + T: Deref, + { + gpio.out_xor.modify(|_, w| w.$pinx().bit(value)); + } + + pub fn invert(gpio: &T) + where + T: Deref, + { + gpio.out_xor.modify(|r, w| w.$pinx().bit(!r.$pinx().bit())); + } + } + ) +} + +pin!(Pin0, pin0); +pin!(Pin1, pin1); +pin!(Pin2, pin2); +pin!(Pin3, pin3); +pin!(Pin4, pin4); +pin!(Pin5, pin5); +pin!(Pin6, pin6); +pin!(Pin7, pin7); +pin!(Pin8, pin8); +pin!(Pin9, pin9); +pin!(Pin10, pin10); +pin!(Pin11, pin11); +pin!(Pin12, pin12); +pin!(Pin13, pin13); +pin!(Pin14, pin14); +pin!(Pin15, pin15); +pin!(Pin16, pin16); +pin!(Pin17, pin17); +pin!(Pin18, pin18); +pin!(Pin19, pin19); +pin!(Pin20, pin20); +pin!(Pin21, pin21); +pin!(Pin22, pin22); +pin!(Pin23, pin23); +pin!(Pin24, pin24); +pin!(Pin25, pin25); +pin!(Pin26, pin26); +pin!(Pin27, pin27); +pin!(Pin28, pin28); +pin!(Pin29, pin29); +pin!(Pin30, pin30); +pin!(Pin31, pin31); diff --git a/src/led.rs b/src/led.rs new file mode 100644 index 0000000..a52d1d8 --- /dev/null +++ b/src/led.rs @@ -0,0 +1,42 @@ +//! User LEDs +//! +//! - Red = Pin 22 +//! - Green = Pin 19 +//! - Blue = Pin 21 + +use e310x::GPIO0; +use gpio::{PinConfig, Pin22, Pin19, Pin21}; + +pub fn init(gpio: &GPIO0) { + Pin22::set_invert(gpio, true); + Pin22::init(gpio, PinConfig::Output); + Pin19::set_invert(gpio, true); + Pin19::init(gpio, PinConfig::Output); + Pin21::set_invert(gpio, true); + Pin21::init(gpio, PinConfig::Output); +} + +#[macro_export] +macro_rules! led { + ($Color:ident, $Pin:ident) => { + pub struct $Color; + + impl $Color { + pub fn on(gpio: &GPIO0) { + $Pin::high(gpio); + } + + pub fn off(gpio: &GPIO0) { + $Pin::low(gpio); + } + + pub fn toggle(gpio: &GPIO0) { + $Pin::toggle(gpio); + } + } + } +} + +led!(Red, Pin22); +led!(Green, Pin19); +led!(Blue, Pin21); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d2ff730 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,225 @@ +#![no_std] +#![feature(asm)] +#![feature(core_intrinsics)] +#![feature(get_type_id)] +#![feature(lang_items)] +#![feature(linkage)] +#![feature(never_type)] +#![feature(used)] + +extern crate embedded_hal as hal; +#[macro_use] +extern crate nb; + +extern crate riscv; +pub extern crate e310x; + +pub mod clint; +pub mod clock; +pub mod gpio; +pub mod led; +pub mod plic; +pub mod pwm; +pub mod serial; +pub mod time; + +use core::fmt::Write; +use riscv::interrupt::Nr; + +pub use hal::prelude; +pub use e310x::Peripherals; +pub use clint::Clint; +pub use led::{Red, Green, Blue}; +pub use plic::{Priority, Interrupt, Plic}; +pub use pwm::{Align, Channel, Pwm}; +pub use serial::{Serial, Port}; +pub use time::UExt; + +/// Initializes the clocks, plic and uart0. Returns Peripherals +/// for application specific initialization. +pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { + let peripherals = unsafe { e310x::Peripherals::all() }; + + // Setup clocks + let clint = Clint(peripherals.CLINT); + let aon_clock = clock::AonClock(peripherals.AONCLK); + unsafe { aon_clock.use_external(); } + let clock = clock::CoreClock(peripherals.PRCI); + unsafe { clock.use_external(&clint); } + + // Setup PLIC + let plic = Plic(peripherals.PLIC); + plic.init(); + + // Initialize UART0 + let serial = Serial(peripherals.UART0); + serial.init(baud_rate.hz().invert(), peripherals.GPIO0); + writeln!(Port(&serial), "Initialized hifive board").unwrap(); + + peripherals +} + +/// Default trap handler +/// +/// Prints trap cause and calls mtimer_trap_handler or plic_trap_handler if +/// necessary. +#[used] +#[no_mangle] +fn trap_handler(trap: riscv::csr::Trap) { + use riscv::csr::{Trap, Interrupt}; + + let peripherals = unsafe { e310x::Peripherals::all() }; + let serial = Serial(peripherals.UART0); + + match trap { + Trap::Interrupt(x) => { + match x { + Interrupt::MachineTimer => { + writeln!(Port(&serial), "MachineTimer").unwrap(); + mtimer_trap_handler(&peripherals); + }, + Interrupt::MachineExternal => { + let plic = Plic(peripherals.PLIC); + let intr = plic.claim(); + + writeln!(Port(&serial), "{:?} {}", intr, intr.nr()).unwrap(); + plic_trap_handler(&peripherals, &intr); + + plic.complete(intr); + } + x => { + writeln!(Port(&serial), "Interrupt {:?}", x).unwrap(); + }, + } + }, + Trap::Exception(x) => { + writeln!(Port(&serial), "Exception {:?}", x).unwrap(); + }, + } +} + +/// Default MachineTimer Trap Handler +#[no_mangle] +#[linkage = "weak"] +fn mtimer_trap_handler(_: &e310x::Peripherals) {} + +/// Default MachineExternal Trap Handler +#[no_mangle] +#[linkage = "weak"] +fn plic_trap_handler(_: &e310x::Peripherals, _: &Interrupt) {} + + +macro_rules! ticks_impl { + ($n:ident, $t:ty, $f:expr) => { + pub const $n: $t = $f as $t; + + impl Ticks<$t> { + /// Applies the function `f` to the inner value + pub fn map(self, f: F) -> Ticks<$t> + where F: FnOnce($t) -> $t, + { + Ticks(f(self.0)) + } + } + + impl From> for Microseconds<$t> { + fn from(ticks: Ticks<$t>) -> Microseconds<$t> { + let divisor: $t = $n / 1_000_000; + Microseconds(ticks.0 / divisor) + } + } + + impl From> for Milliseconds<$t> { + fn from(ticks: Ticks<$t>) -> Milliseconds<$t> { + Milliseconds(ticks.0 / ($n / 1_000)) + } + } + + impl From> for Seconds<$t> { + fn from(ticks: Ticks<$t>) -> Seconds<$t> { + Seconds(ticks.0 / $n) + } + } + + impl From> for Ticks<$t> { + fn from(ihz: IHertz<$t>) -> Ticks<$t> { + Ticks($n / ihz.0) + } + } + + impl From> for Ticks<$t> { + fn from(us: Microseconds<$t>) -> Ticks<$t> { + Ticks(us.0 * ($n / 1_000_000)) + } + } + + impl From> for Ticks<$t> { + fn from(ms: Milliseconds<$t>) -> Ticks<$t> { + Ticks(ms.0 * ($n / 1_000)) + } + } + + impl From> for Ticks<$t> { + fn from(s: Seconds<$t>) -> Ticks<$t> { + Ticks(s.0 * $n) + } + } + + impl Into<$t> for Ticks<$t> { + fn into(self) -> $t { + self.0 + } + } + + impl ::core::ops::Add for Ticks<$t> { + type Output = Ticks<$t>; + + fn add(self, other: Ticks<$t>) -> Ticks<$t> { + Ticks(self.0 + other.0) + } + } + + impl ::core::ops::Sub for Ticks<$t> { + type Output = Ticks<$t>; + + fn sub(self, other: Ticks<$t>) -> Ticks<$t> { + Ticks(self.0 - other.0) + } + } + } +} + +macro_rules! frequency { + ($FREQUENCY:expr) => { + use time::*; + + /// Unit of time + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] + pub struct Ticks(pub T); + + ticks_impl!(FREQUENCY_32, u32, $FREQUENCY); + ticks_impl!(FREQUENCY_64, u64, $FREQUENCY); + + impl Into for Ticks { + fn into(self) -> u32 { + self.0 as u32 + } + } + + impl Ticks { + pub fn into_hi(self) -> u32 { + (self.0 >> 32) as u32 + } + } + } +} + +/// Always-On Clock +pub mod aonclk { + frequency!(32_768); +} + +/// Core Clock +pub mod coreclk { + frequency!(16_000_000); +} diff --git a/src/plic.rs b/src/plic.rs new file mode 100644 index 0000000..8130cc6 --- /dev/null +++ b/src/plic.rs @@ -0,0 +1,125 @@ +use riscv::interrupt::Nr; +use e310x::PLIC; +pub use e310x::Interrupt; + +pub enum Priority { + Never, P1, P2, P3, P4, P5, P6, P7, +} + +impl Priority { + pub fn from(prio: u32) -> Priority { + match prio { + 0 => Priority::Never, + 1 => Priority::P1, + 2 => Priority::P2, + 3 => Priority::P3, + 4 => Priority::P4, + 5 => Priority::P5, + 6 => Priority::P6, + 7 => Priority::P7, + _ => unreachable!(), + } + } +} + +impl Into for Priority { + fn into(self) -> u32 { + match self { + Priority::Never => 0, + Priority::P1 => 1, + Priority::P2 => 2, + Priority::P3 => 3, + Priority::P4 => 4, + Priority::P5 => 5, + Priority::P6 => 6, + Priority::P7 => 7, + } + } +} + +pub struct Plic<'a>(pub &'a PLIC); + +impl<'a> Clone for Plic<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Copy for Plic<'a> { +} + +impl<'a> Plic<'a> { + pub fn init(&self) { + for reg in self.0.enable.iter() { + unsafe { + reg.write(|w| w.bits(0)); + } + } + //interrupt!(MachineExternal, plic::plic_handler()); + } + + /*pub fn handler(&self, f: F) where F: Fn { + let intr = plic.claim(); + f(intr); + plic.complete(intr); + }*/ + + pub fn is_pending(&self, intr: Interrupt) -> bool { + let mask = 1 << (intr.nr() % 32); + let pending = self.0.pending[(intr.nr() / 32) as usize].read(); + pending.bits() & mask == mask + } + + pub fn is_enabled(&self, intr: Interrupt) -> bool { + let mask = 1 << (intr.nr() % 32); + let enable = self.0.enable[(intr.nr() / 32) as usize].read(); + enable.bits() & mask == mask + } + + pub fn enable(&self, intr: Interrupt) { + let mask = 1 << (intr.nr() % 32); + unsafe { + self.0.enable[(intr.nr() / 32) as usize] + .modify(|r, w| w.bits(r.bits() | mask)); + } + } + + pub fn disable(&self, intr: Interrupt) { + let mask = 1 << (intr.nr() % 32); + unsafe { + self.0.enable[(intr.nr() / 32) as usize] + .modify(|r, w| w.bits(r.bits() & !mask)); + } + } + + pub fn claim(&self) -> Interrupt { + Interrupt::from(self.0.claim.read().bits() as u8) + } + + pub fn complete(&self, intr: Interrupt) { + unsafe { + self.0.claim.write(|w| w.bits(intr.nr() as u32)); + } + } + + pub fn get_priority(&self, intr: Interrupt) -> Priority { + Priority::from(self.0.priority[(intr.nr() - 1) as usize].read().bits()) + } + + pub fn set_priority(&self, intr: Interrupt, prio: Priority) { + unsafe { + self.0.priority[(intr.nr() - 1) as usize] + .write(|w| w.bits(prio.into())); + } + } + + pub fn get_threshold(&self) -> Priority { + Priority::from(self.0.threshold.read().bits()) + } + + pub fn set_threshold(&self, prio: Priority) { + unsafe { + self.0.threshold.write(|w| w.bits(prio.into())); + } + } +} diff --git a/src/pwm.rs b/src/pwm.rs new file mode 100644 index 0000000..a105226 --- /dev/null +++ b/src/pwm.rs @@ -0,0 +1,515 @@ +//! Pulse Width Modulation +//! +//! You can use the `Pwm` interface with these PWM instances +//! +//! # PWM0 +//! +//! - CH0: Pin 0 IOF1 +//! - CH1: Pin 1 IOF1 +//! - CH2: Pin 2 IOF1 +//! - CH3: Pin 3 IOF1 +//! +//! # PWM1 +//! +//! - CH0: Pin 20 IOF1 +//! - CH1: Pin 19 IOF1 +//! - CH2: Pin 21 IOF1 +//! - CH3: Pin 22 IOF1 +//! +//! # PWM2 +//! +//! - CH0: Pin 10 IOF1 +//! - CH1: Pin 11 IOF1 +//! - CH2: Pin 12 IOF1 +//! - CH3: Pin 13 IOF1 + +use core::any::{Any, TypeId}; +use core::ops::Deref; + +use e310x::{pwm0, PWM0, PWM1, PWM2, gpio0, GPIO0}; +use gpio::{PinConfig, Pin0, Pin1, Pin2, Pin3, Pin20, Pin19, + Pin21, Pin22, Pin10, Pin11, Pin12, Pin13}; + +/// Channel +#[derive(Clone, Copy, Debug)] +pub enum Channel { + /// CH0 + _0, + /// CH1 + _1, + /// CH2 + _2, + /// CH3 + _3, +} + +/// Channel +#[derive(Clone, Copy, Debug)] +pub enum Align { + /// Left + Left, + /// Center + Center, + /// Right + Right, +} + +/// IMPLEMENTATION DETAIL +pub unsafe trait PWM: Deref { + /// IMPLEMENTATION DETAIL + type GPIO: Deref; +} + +unsafe impl PWM for PWM0 { + type GPIO = GPIO0; +} + +unsafe impl PWM for PWM1 { + type GPIO = GPIO0; +} + +unsafe impl PWM for PWM2 { + type GPIO = GPIO0; +} + +pub struct Pwm<'a, T>(pub &'a T) + where + T: 'a; + +impl<'a, T> Clone for Pwm<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for Pwm<'a, T> {} + +impl<'a, T> Pwm<'a, T> + where + T: Any + PWM, +{ + pub fn init(&self) { + unsafe { + self.0.cfg.modify(|_, w| { + w.enalways().bit(true) + // set period of 1s + .scale().bits(8) + .zerocmp().bit(true) + }); + self.0.count.write(|w| w.bits(0)); + } + } + + pub fn enable(&self, channel: Channel, align: Align, gpio: &T::GPIO) { + if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => { + Pin0::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin0::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin0::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin0::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_1 => { + Pin1::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin1::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin1::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin1::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_2 => { + Pin2::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin2::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin2::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin2::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_3 => { + Pin3::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin3::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin3::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin3::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => { + Pin20::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin20::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin20::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin20::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_1 => { + Pin19::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin19::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin19::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin19::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_2 => { + Pin21::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin21::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin21::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin21::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_3 => { + Pin22::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin22::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin22::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin22::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => { + Pin10::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin10::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin10::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin10::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_1 => { + Pin11::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin11::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin11::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin11::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_2 => { + Pin12::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin12::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin12::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin12::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + Channel::_3 => { + Pin13::init(gpio, PinConfig::IoFn1); + match align { + Align::Left => { + Pin13::set_invert(gpio, true); + self.set_center(channel, false); + }, + Align::Center => { + Pin13::set_invert(gpio, false); + self.set_center(channel, true); + }, + Align::Right => { + Pin13::set_invert(gpio, false); + self.set_center(channel, false); + } + } + }, + } + } + } + + pub fn disable(&self, channel: Channel, gpio: &T::GPIO) { + if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin0::init(gpio, PinConfig::Input), + Channel::_1 => Pin1::init(gpio, PinConfig::Input), + Channel::_2 => Pin2::init(gpio, PinConfig::Input), + Channel::_3 => Pin3::init(gpio, PinConfig::Input), + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin20::init(gpio, PinConfig::Input), + Channel::_1 => Pin19::init(gpio, PinConfig::Input), + Channel::_2 => Pin21::init(gpio, PinConfig::Input), + Channel::_3 => Pin22::init(gpio, PinConfig::Input), + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin10::init(gpio, PinConfig::Input), + Channel::_1 => Pin11::init(gpio, PinConfig::Input), + Channel::_2 => Pin12::init(gpio, PinConfig::Input), + Channel::_3 => Pin13::init(gpio, PinConfig::Input), + } + } + } + + pub fn invert(&self, channel: Channel, gpio: &T::GPIO) { + if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin0::invert(gpio), + Channel::_1 => Pin1::invert(gpio), + Channel::_2 => Pin2::invert(gpio), + Channel::_3 => Pin3::invert(gpio), + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin20::invert(gpio), + Channel::_1 => Pin19::invert(gpio), + Channel::_2 => Pin21::invert(gpio), + Channel::_3 => Pin22::invert(gpio), + } + } else if self.0.get_type_id() == TypeId::of::() { + match channel { + Channel::_0 => Pin10::invert(gpio), + Channel::_1 => Pin11::invert(gpio), + Channel::_2 => Pin12::invert(gpio), + Channel::_3 => Pin13::invert(gpio), + } + } + } + + pub fn set_period

(&self, period: P) + where P: Into<::coreclk::Ticks> + { + let ticks: u32 = period.into().into(); + let scale = u16::max_value() as u32 / ticks; + assert!(scale < 0x10); + ::riscv::asm::ebreak(); + unsafe { + self.0.cfg.modify(|_, w| w.scale().bits(scale as u8)); + } + } + + pub fn get_period(&self) -> ::coreclk::Ticks { + let scale = self.0.cfg.read().scale().bits(); + ::coreclk::Ticks(scale as u32 * u16::max_value() as u32) + } + + pub fn align_left(&self, channel: Channel, gpio: &T::GPIO) { + match channel { + Channel::_0 => { + self.0.cfg.modify(|_, w| w.cmp0center().bit(false)); + self.invert(channel, gpio); + }, + Channel::_1 => { + self.0.cfg.modify(|_, w| w.cmp1center().bit(false)); + self.invert(channel, gpio); + }, + Channel::_2 => { + self.0.cfg.modify(|_, w| w.cmp2center().bit(false)); + self.invert(channel, gpio); + } + Channel::_3 => { + self.0.cfg.modify(|_, w| w.cmp3center().bit(false)); + self.invert(channel, gpio); + } + } + } + + fn set_center(&self, channel: Channel, value: bool) { + match channel { + Channel::_0 => self.0.cfg.modify(|_, w| w.cmp0center().bit(value)), + Channel::_1 => self.0.cfg.modify(|_, w| w.cmp1center().bit(value)), + Channel::_2 => self.0.cfg.modify(|_, w| w.cmp2center().bit(value)), + Channel::_3 => self.0.cfg.modify(|_, w| w.cmp3center().bit(value)), + } + } + + pub fn get_cmp(&self, channel: Channel) -> u16 { + match channel { + Channel::_0 => self.0.cmp0.read().value().bits(), + Channel::_1 => self.0.cmp1.read().value().bits(), + Channel::_2 => self.0.cmp2.read().value().bits(), + Channel::_3 => self.0.cmp3.read().value().bits(), + } + } + + pub fn set_cmp(&self, channel: Channel, cmp: u16) { + unsafe { + match channel { + Channel::_0 => self.0.cmp0.write(|w| w.value().bits(cmp)), + Channel::_1 => self.0.cmp1.write(|w| w.value().bits(cmp)), + Channel::_2 => self.0.cmp2.write(|w| w.value().bits(cmp)), + Channel::_3 => self.0.cmp3.write(|w| w.value().bits(cmp)), + } + } + } +} + +/* +/// `hal::Pwm` implementation +impl<'a, T> hal::Pwm for Pwm<'a, T> + where + T: Any + PWM, +{ + type Channel = Channel; + type Duty = u16; + type Time = ::coreclk::Ticks; + + fn get_duty(&self, channel: Channel) -> u16 { + self.get_cmp(channel) + } + + fn disable(&self, channel: Channel) { + + } + + fn enable(&self, channel: Channel) { + + } + + fn get_max_duty(&self) -> u16 { + u16::max_value() + } + + fn get_period(&self) -> ::coreclk::Ticks { + self.get_period() + } + + fn set_duty(&self, channel: Channel, duty: u16) { + self.set_cmp(channel, duty); + } + + fn set_period

(&self, period: P) + where + P: Into<::coreclk::Ticks>, + { + self.set_period(period.into()); + } +} + +#[allow(unused_variables)] +/// `hal::Timer` implementation +impl<'a, T> hal::Timer for Pwm<'a, T> + where + T: Any + PWM +{ + type Time = ::coreclk::Ticks; + + fn get_timeout(&self) -> ::coreclk::Ticks { + ::coreclk::Ticks(10) + } + + fn pause(&self) { + + } + + fn restart(&self) { + + } + + fn resume(&self) { + + } + + fn set_timeout(&self, timeout: TO) + where + TO: Into<::coreclk::Ticks>, + { + + } + + fn wait(&self) -> nb::Result<(), !> { + Ok(()) + } +} +*/ diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 0000000..0008043 --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,151 @@ +//! Serial interface +//! +//! You can use the `Serial` interface with these UART instances +//! +//! # UART0 +//! - TX: Pin 17 IOF0 +//! - RX: Pin 16 IOF0 +//! - Interrupt::UART0 +//! +//! # UART1 +//! - TX: Pin 25 IOF0 +//! - RX: Pin 24 IOF0 +//! - Interrupt::UART1 + + +use core::any::{Any, TypeId}; +use core::ops::Deref; +use e310x::{gpio0, GPIO0, uart0, UART0, UART1}; +use gpio::{PinConfig, Pin17, Pin16, Pin25, Pin24}; + +/// IMPLEMENTATION DETAIL +pub unsafe trait Uart: Deref { + /// IMPLEMENTATION DETAIL + type GPIO: Deref; + type Ticks: Into; +} + +unsafe impl Uart for UART0 { + type GPIO = GPIO0; + type Ticks = ::coreclk::Ticks; +} + +unsafe impl Uart for UART1 { + type GPIO = GPIO0; + type Ticks = ::coreclk::Ticks; +} + +/// Serial interface +pub struct Serial<'a, U>(pub &'a U) +where + U: Any + Uart; + +impl<'a, U> Clone for Serial<'a, U> +where + U: Any + Uart, +{ + fn clone(&self) -> Self { + *self + } +} + +impl<'a, U> Copy for Serial<'a, U> +where + U: Any + Uart, +{ +} + +impl<'a, U> Serial<'a, U> +where + U: Any + Uart, +{ + /// Initializes the serial interface with a baud rate of `baud_rate` bits + /// per second + pub fn init(&self, baud_rate: B, gpio: &U::GPIO) + where B: Into, + { + if self.0.get_type_id() == TypeId::of::() { + Pin16::init(gpio, PinConfig::IoFn0); + Pin17::init(gpio, PinConfig::IoFn0); + } else if self.0.get_type_id() == TypeId::of::() { + Pin24::init(gpio, PinConfig::IoFn0); + Pin25::init(gpio, PinConfig::IoFn0); + } + + unsafe { + let div = baud_rate.into().into(); + self.0.div.write(|w| w.bits(div)); + + self.0.txctrl.write(|w| w.enable().bit(true)); + self.0.rxctrl.write(|w| w.enable().bit(true)); + } + } +} + +impl<'a, U> ::hal::serial::Read for Serial<'a, U> +where + U: Any + Uart, +{ + type Error = !; + + fn read(&self) -> ::nb::Result { + let uart = self.0; + let rxdata = uart.rxdata.read(); + + if rxdata.empty().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits() as u8) + } + } +} + +impl<'a, U> ::hal::serial::Write for Serial<'a, U> +where + U: Any + Uart, +{ + type Error = !; + + fn write(&self, byte: u8) -> ::nb::Result<(), !> { + let uart = self.0; + let txdata = uart.txdata.read(); + + if txdata.full().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + unsafe { + uart.txdata.write(|w| w.data().bits(byte)); + } + Ok(()) + } + } +} + +/// Port +pub struct Port<'p, T>(pub &'p T) + where + T: 'p; + +impl<'p, T> ::core::fmt::Write for Port<'p, T> + where + T: ::hal::serial::Write, +{ + fn write_str(&mut self, s: &str) -> ::core::fmt::Result { + for byte in s.as_bytes() { + let res = block!(self.0.write(*byte)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + + if *byte == '\n' as u8 { + let res = block!(self.0.write('\r' as u8)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + } + } + Ok(()) + } +} diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..ed86a9f --- /dev/null +++ b/src/time.rs @@ -0,0 +1,110 @@ +//! Units of time + +macro_rules! map { + ($Self:ident) => { + impl $Self { + /// Applies the function `f` to inner value + pub fn map(self, f: F) -> $Self + where + F: FnOnce(T) -> T + { + $Self(f(self.0)) + } + } + } +} + +/// `Hz^-1` +#[derive(Clone, Copy, Debug)] +pub struct IHertz(pub T); + +impl IHertz { + /// Invert this quantity + pub fn invert(self) -> Hertz { + Hertz(self.0) + } +} + +map!(IHertz); + +/// `Hz` +#[derive(Clone, Copy, Debug)] +pub struct Hertz(pub T); + +impl Hertz { + /// Invert this quantity + pub fn invert(self) -> IHertz { + IHertz(self.0) + } +} + +map!(Hertz); + +/// `us` +#[derive(Clone, Copy, Debug)] +pub struct Microseconds(pub T); + +map!(Microseconds); + +/// `ms` +#[derive(Clone, Copy, Debug)] +pub struct Milliseconds(pub T); + +map!(Milliseconds); + +/// `s` +#[derive(Clone, Copy, Debug)] +pub struct Seconds(pub T); + +map!(Seconds); + +/// `u32` and `u64` extension trait +pub trait UExt { + /// Wrap in `Hz` + fn hz(self) -> Hertz; + + /// Wrap in `Milliseconds` + fn ms(self) -> Milliseconds; + + /// Wrap in `Seconds` + fn s(self) -> Seconds; + + /// Wrap in `Microseconds` + fn us(self) -> Microseconds; +} + +impl UExt for u32 { + fn hz(self) -> Hertz { + Hertz(self) + } + + fn ms(self) -> Milliseconds { + Milliseconds(self) + } + + fn s(self) -> Seconds { + Seconds(self) + } + + fn us(self) -> Microseconds { + Microseconds(self) + } +} + +impl UExt for u64 { + fn hz(self) -> Hertz { + Hertz(self) + } + + fn ms(self) -> Milliseconds { + Milliseconds(self) + } + + fn s(self) -> Seconds { + Seconds(self) + } + + fn us(self) -> Microseconds { + Microseconds(self) + } +} From cc1da45e80da5588732b4bde43eadf1743dbb35b Mon Sep 17 00:00:00 2001 From: David Craven Date: Mon, 20 Nov 2017 09:36:22 +0100 Subject: [PATCH 002/315] Remove unneeded feature. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d2ff730..ca57aac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] #![feature(asm)] -#![feature(core_intrinsics)] #![feature(get_type_id)] #![feature(lang_items)] #![feature(linkage)] From 7750e352f0a8ab9ca6f7d0b5056d67ccf3cbd41a Mon Sep 17 00:00:00 2001 From: David Craven Date: Mon, 20 Nov 2017 13:27:42 +0100 Subject: [PATCH 003/315] Cleanup. --- Makefile | 8 +++----- examples/panicking.rs | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 0ce4811..7cde44e 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,6 @@ EXAMPLE := blinky_delay #EXAMPLE := blinky_plic #EXAMPLE := hello_world #EXAMPLE := panicking -#EXAMPLE := heaps -#EXAMPLE := rtc -#EXAMPLE := watchdog -#EXAMPLE := utest -#EXAMPLE := rtfm # Board crate (uncomment one) BOARD := hifive @@ -48,4 +43,7 @@ upload: openocd -f $(OPENOCD_CFG) \ -c "flash protect 0 64 last off; program ${EXAMPLE_BIN}; resume 0x20400000; exit" +framedump: + riscv32-unknown-elf-readelf --debug-dump=frames $(EXAMPLE_BIN) $(ARGS) + .PHONY: build clean readelf objdump framedump size gdb openocd spike diff --git a/examples/panicking.rs b/examples/panicking.rs index 5dba0f9..480534f 100644 --- a/examples/panicking.rs +++ b/examples/panicking.rs @@ -15,6 +15,5 @@ fn one() { } fn main() { - hifive::init(115_200); one(); } From a554b5e0d89f9eb29451500298e39bbc13469ace Mon Sep 17 00:00:00 2001 From: David Craven Date: Mon, 20 Nov 2017 14:32:27 +0100 Subject: [PATCH 004/315] Use git versions. --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index acabf39..29d8477 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,15 +15,15 @@ rev = "7d904f515d15fd5fe7ea34e18820ea83e2651fa2" [dependencies.nb] git = "https://github.com/japaric/nb" -[dependencies.e310x] -features = ["rt"] -version = "^0.1.1" - [dependencies.riscv] -version = "^0.1.3" +git = "https://github.com/dvc94ch/riscv" -[dev-dependencies.riscv-rt] -version = "^0.1.3" +[dependencies.riscv-rt] +git = "https://github.com/dvc94ch/riscv-rt" + +[dependencies.e310x] +features = ["rt"] +git = "https://github.com/dvc94ch/e310x" [profile.release] debug = true From f20ece3907f50f817dbccf0c155be108b94ee747 Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 21 Nov 2017 10:25:58 +0100 Subject: [PATCH 005/315] Enable interrupts. --- examples/blinky_clint.rs | 6 +++++- examples/blinky_plic.rs | 7 ++++++- src/lib.rs | 14 ++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/examples/blinky_clint.rs b/examples/blinky_clint.rs index f96cfdc..3798ccf 100644 --- a/examples/blinky_clint.rs +++ b/examples/blinky_clint.rs @@ -3,7 +3,7 @@ extern crate hifive; use hifive::prelude::*; -use hifive::{led, Blue, Clint, Peripherals, UExt}; +use hifive::{interrupt, led, Blue, Clint, Peripherals, UExt}; fn main() { let peripherals = hifive::init(115_200); @@ -11,6 +11,10 @@ fn main() { let timer = Clint(peripherals.CLINT); timer.set_timeout(1.s()); + + unsafe { + interrupt::enable(); + } } #[no_mangle] diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs index 86c92e5..e2b90e7 100644 --- a/examples/blinky_plic.rs +++ b/examples/blinky_plic.rs @@ -2,7 +2,8 @@ extern crate hifive; -use hifive::{led, Red, Blue, Green, Interrupt, Plic, Channel, Pwm, Peripherals}; +use hifive::{interrupt, led, Red, Blue, Green, Interrupt, Plic, + Channel, Pwm, Peripherals}; fn main() { let peripherals = hifive::init(115_200); @@ -19,6 +20,10 @@ fn main() { plic.enable(Interrupt::PWM0CMP1); plic.enable(Interrupt::PWM0CMP2); plic.enable(Interrupt::PWM0CMP3); + + unsafe { + interrupt::enable(); + } } #[no_mangle] diff --git a/src/lib.rs b/src/lib.rs index ca57aac..86078b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ use core::fmt::Write; use riscv::interrupt::Nr; pub use hal::prelude; +pub use riscv::{csr, interrupt}; pub use e310x::Peripherals; pub use clint::Clint; pub use led::{Red, Green, Blue}; @@ -64,7 +65,7 @@ pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { /// necessary. #[used] #[no_mangle] -fn trap_handler(trap: riscv::csr::Trap) { +pub fn trap_handler(trap: riscv::csr::Trap) { use riscv::csr::{Trap, Interrupt}; let peripherals = unsafe { e310x::Peripherals::all() }; @@ -81,18 +82,19 @@ fn trap_handler(trap: riscv::csr::Trap) { let plic = Plic(peripherals.PLIC); let intr = plic.claim(); - writeln!(Port(&serial), "{:?} {}", intr, intr.nr()).unwrap(); + writeln!(Port(&serial), "{}", intr.nr()).unwrap(); plic_trap_handler(&peripherals, &intr); plic.complete(intr); } x => { - writeln!(Port(&serial), "Interrupt {:?}", x).unwrap(); + writeln!(Port(&serial), "Interrupt {}", x as u32).unwrap(); }, } }, Trap::Exception(x) => { - writeln!(Port(&serial), "Exception {:?}", x).unwrap(); + let mepc = csr::mepc.read().bits(); + writeln!(Port(&serial), "Exception {} at 0x{:x}", x as u32, mepc).unwrap(); }, } } @@ -100,12 +102,12 @@ fn trap_handler(trap: riscv::csr::Trap) { /// Default MachineTimer Trap Handler #[no_mangle] #[linkage = "weak"] -fn mtimer_trap_handler(_: &e310x::Peripherals) {} +pub fn mtimer_trap_handler(_: &e310x::Peripherals) {} /// Default MachineExternal Trap Handler #[no_mangle] #[linkage = "weak"] -fn plic_trap_handler(_: &e310x::Peripherals, _: &Interrupt) {} +pub fn plic_trap_handler(_: &e310x::Peripherals, _: &Interrupt) {} macro_rules! ticks_impl { From 39e9e520b16f8238e562a150863e975e7ec13fd5 Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 21 Nov 2017 13:44:31 +0100 Subject: [PATCH 006/315] Clean up PLIC code. --- src/lib.rs | 6 +----- src/plic.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 86078b2..13c3c23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,10 +47,6 @@ pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { let clock = clock::CoreClock(peripherals.PRCI); unsafe { clock.use_external(&clint); } - // Setup PLIC - let plic = Plic(peripherals.PLIC); - plic.init(); - // Initialize UART0 let serial = Serial(peripherals.UART0); serial.init(baud_rate.hz().invert(), peripherals.GPIO0); @@ -82,7 +78,7 @@ pub fn trap_handler(trap: riscv::csr::Trap) { let plic = Plic(peripherals.PLIC); let intr = plic.claim(); - writeln!(Port(&serial), "{}", intr.nr()).unwrap(); + writeln!(Port(&serial), "ExternalInterrupt {}", intr.nr()).unwrap(); plic_trap_handler(&peripherals, &intr); plic.complete(intr); diff --git a/src/plic.rs b/src/plic.rs index 8130cc6..518b031 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -1,3 +1,4 @@ +use riscv::csr; use riscv::interrupt::Nr; use e310x::PLIC; pub use e310x::Interrupt; @@ -49,20 +50,23 @@ impl<'a> Copy for Plic<'a> { } impl<'a> Plic<'a> { - pub fn init(&self) { + /*pub fn init(&self) { for reg in self.0.enable.iter() { unsafe { reg.write(|w| w.bits(0)); } } + //interrupt!(MachineExternal, plic::plic_handler()); + }*/ + + pub fn enable_mexternal(&self) { + csr::mie.set(|w| w.mext()); } - /*pub fn handler(&self, f: F) where F: Fn { - let intr = plic.claim(); - f(intr); - plic.complete(intr); - }*/ + pub fn clear_mexternal(&self) { + csr::mie.clear(|w| w.mext()); + } pub fn is_pending(&self, intr: Interrupt) -> bool { let mask = 1 << (intr.nr() % 32); From d2eeacdce0aba84373134d30d26d732e26731468 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 22 Nov 2017 10:20:02 +0100 Subject: [PATCH 007/315] Refactor clock.rs `use_external` and `use_pll` now use `init_pll`. `use_pll` configures the pll to 256MHz, the maximum possible with an external 16MHz clock. Added `pll_mult` to compute the configured clock multiplier and an example. --- Makefile | 6 ++++-- examples/pll.rs | 27 ++++++++++++++++++++++++ src/clock.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 examples/pll.rs diff --git a/Makefile b/Makefile index 7cde44e..027d085 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,19 @@ # Examples (uncomment one) -EXAMPLE := blinky_delay +#EXAMPLE := blinky_delay #EXAMPLE := blinky_clint #EXAMPLE := blinky_pwm #EXAMPLE := blinky_plic #EXAMPLE := hello_world #EXAMPLE := panicking +#EXAMPLE := pll # Board crate (uncomment one) BOARD := hifive TARGET := riscv32-unknown-none TARGET_DIR := $(abspath ./target/$(TARGET)/debug) -EXAMPLE_BIN := $(TARGET_DIR)/examples/$(EXAMPLE) +EXAMPLE_DIR := $(TARGET_DIR)/examples +EXAMPLE_BIN := $(EXAMPLE_DIR)/$(EXAMPLE) OPENOCD_CFG := $(wildcard $(TARGET_DIR)/build/$(BOARD)-*/out/openocd.cfg) build: diff --git a/examples/pll.rs b/examples/pll.rs new file mode 100644 index 0000000..054efa1 --- /dev/null +++ b/examples/pll.rs @@ -0,0 +1,27 @@ +#![no_std] + +extern crate hifive; + +use core::fmt::Write; +use hifive::{clock, Clint, Port, Serial}; + +fn main() { + let p = hifive::init(115_200); + + let serial = Serial(p.UART0); + let mut stdout = Port(&serial); + writeln!(stdout, "Setting up PLL").unwrap(); + + let clint = Clint(p.CLINT); + let clock = clock::CoreClock(p.PRCI); + + let freq_calc_default = clock.pll_mult() * 16; + unsafe { clock.use_pll(&clint); } + let freq_calc = clock.pll_mult() * 16; + let freq_measured = clock.measure(&clint) / 1_000_000; + unsafe { clock.use_external(&clint); } + + writeln!(stdout, "Default PLL settings {}MHz", freq_calc_default).unwrap(); + writeln!(stdout, "Measured clock frequency of {}MHz", freq_measured).unwrap(); + writeln!(stdout, "Computed clock frequency of {}MHz", freq_calc).unwrap(); +} diff --git a/src/clock.rs b/src/clock.rs index 46e36b6..50ec9d2 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -14,7 +14,7 @@ impl<'a> Clone for AonClock<'a> { impl<'a> Copy for AonClock<'a> {} impl<'a> AonClock<'a> { - /// Use external real time oscillator + /// Use external real time oscillator. pub unsafe fn use_external(&self) { // The G000 doesn't have a LFXOSC and is hardwired // to use the an external oscillator. @@ -36,15 +36,60 @@ impl<'a> Copy for CoreClock<'a> { } impl<'a> CoreClock<'a> { + /// Use external oscillator with bypassed pll. pub unsafe fn use_external(&self, clint: &Clint) { - self.use_pll(clint, |_, w| { + self.init_pll(clint, |_, w| { // bypass PLL w.bypass().bit(true) // select HFXOSC .refsel().bit(true) }, |w| w.divby1().bit(true)); + // Disable HFROSC to save power + self.0.hfrosccfg.write(|w| w.enable().bit(false)); + } + + /// Use external oscillator with pll. Sets PLL + /// r=2, f=64, q=2 values to maximum allowable + /// for a 16MHz reference clock. Output frequency + /// is 16MHz / 2 * 64 / 2 = 256MHz. + /// NOTE: By trimming the internal clock to 12MHz + /// and using r=1, f=64, q=2 the maximum frequency + /// of 384MHz can be reached. + pub unsafe fn use_pll(&self, clint: &Clint) { + self.init_pll(clint, |_, w| { + // bypass PLL + w.bypass().bit(false) + // select HFXOSC + .refsel().bit(true) + // bits = r - 1 + .pllr().bits(1) + // bits = f / 2 - 1 + .pllf().bits(31) + // bits = q=2 -> 1, q=4 -> 2, q=8 -> 3 + .pllq().bits(1) + }, |w| w.divby1().bit(true)); + // Disable HFROSC to save power + self.0.hfrosccfg.write(|w| w.enable().bit(false)); + } + + /// Compute PLL multiplier. + pub fn pll_mult(&self) -> u32 { + let pllcfg = self.0.pllcfg.read(); + let plloutdiv = self.0.plloutdiv.read(); + + let r = pllcfg.pllr().bits() as u32 + 1; + let f = (pllcfg.pllf().bits() as u32 + 1) * 2; + let q = [2, 4, 8][pllcfg.pllq().bits() as usize - 1]; + + let div = match plloutdiv.divby1().bit() { + true => 1, + false => (plloutdiv.div().bits() as u32 + 1) * 2, + }; + + f / r / q / div } + /// Wait for the pll to lock. unsafe fn wait_for_lock(&self, clint: &Clint) { // Won't lock when bypassed and will loop forever if !self.0.pllcfg.read().bypass().bit_is_set() { @@ -60,7 +105,7 @@ impl<'a> CoreClock<'a> { } } - pub unsafe fn use_pll(&self, clint: &Clint, pllcfg: F, plloutdiv: G) + unsafe fn init_pll(&self, clint: &Clint, pllcfg: F, plloutdiv: G) where for<'w> F: FnOnce(&prci::pllcfg::R, &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, @@ -82,10 +127,9 @@ impl<'a> CoreClock<'a> { self.0.pllcfg.modify(|_, w| { w.sel().bit(true) }); - // Disable HFROSC to save power - self.0.hfrosccfg.write(|w| w.enable().bit(false)); } + /// Use internal oscillator with bypassed pll. pub unsafe fn use_internal(&self) { // Enable HFROSC self.0.hfrosccfg.write(|w| { @@ -111,6 +155,7 @@ impl<'a> CoreClock<'a> { self.0.hfxosccfg.write(|w| w.enable().bit(false)); } + /// Measure the frequency of coreclk. pub fn measure(&self, clint: &Clint) -> u32 { // warm up I$ clint.measure_coreclk(::aonclk::Ticks(1)); From 9263484b2d80fb4ced3e2cd9b3331c12a7050330 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 22 Nov 2017 11:22:22 +0100 Subject: [PATCH 008/315] Document Plic driver. --- examples/blinky_plic.rs | 49 +++++++++---------- src/plic.rs | 104 ++++++++++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 50 deletions(-) diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs index e2b90e7..fb75591 100644 --- a/examples/blinky_plic.rs +++ b/examples/blinky_plic.rs @@ -2,46 +2,43 @@ extern crate hifive; -use hifive::{interrupt, led, Red, Blue, Green, Interrupt, Plic, - Channel, Pwm, Peripherals}; +use core::fmt::Write; +use hifive::*; +use hifive::prelude::*; +use hifive::interrupt::Nr; fn main() { - let peripherals = hifive::init(115_200); - led::init(peripherals.GPIO0); + let p = hifive::init(115_200); + led::init(p.GPIO0); - let pwm = Pwm(peripherals.PWM0); - pwm.init(); - pwm.set_cmp(Channel::_0, u16::max_value()); - pwm.set_cmp(Channel::_1, 0); - pwm.set_cmp(Channel::_2, u16::max_value() / 2); + Red::on(p.GPIO0); - let plic = Plic(peripherals.PLIC); - plic.enable(Interrupt::PWM0CMP0); - plic.enable(Interrupt::PWM0CMP1); - plic.enable(Interrupt::PWM0CMP2); - plic.enable(Interrupt::PWM0CMP3); + let plic = Plic(p.PLIC); + plic.init(); + + RtcConf::new().end(p.RTC); + Rtc(p.RTC).set_timeout(500.ms()); + + plic.set_priority(Interrupt::RTC, Priority::P7); + plic.enable(Interrupt::RTC); + + let serial = Serial(p.UART0); + let mut stdout = Port(&serial); + writeln!(stdout, "RTC interrupt is set {}", plic.is_enabled(Interrupt::RTC)).unwrap(); + writeln!(stdout, "RTC interrupt nr is {}", Interrupt::RTC.nr()).unwrap(); unsafe { interrupt::enable(); } + + loop {} } #[no_mangle] pub fn plic_trap_handler(p: &Peripherals, intr: &Interrupt) { - //let pwm = Pwm(p.PWM0); - match *intr { - Interrupt::PWM0CMP0 => { + Interrupt::RTC => { Blue::toggle(p.GPIO0); - }, - Interrupt::PWM0CMP1 => { - Green::toggle(p.GPIO0); - }, - Interrupt::PWM0CMP2 => { - Red::toggle(p.GPIO0); - }, - Interrupt::PWM0CMP3 => { - }, _ => {}, } diff --git a/src/plic.rs b/src/plic.rs index 518b031..b2a4f31 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -3,14 +3,18 @@ use riscv::interrupt::Nr; use e310x::PLIC; pub use e310x::Interrupt; +/// Priority of a plic::Interrupt. +#[derive(Clone, Copy)] pub enum Priority { - Never, P1, P2, P3, P4, P5, P6, P7, + P0, P1, P2, P3, P4, P5, P6, P7, } impl Priority { - pub fn from(prio: u32) -> Priority { + /// Takes a read interrupt priority or plic threshold + /// register value and returns a plic::Priority enum. + fn from(prio: u32) -> Priority { match prio { - 0 => Priority::Never, + 0 => Priority::P0, 1 => Priority::P1, 2 => Priority::P2, 3 => Priority::P3, @@ -24,9 +28,11 @@ impl Priority { } impl Into for Priority { + /// Returns the numeric priority for wirting to a + /// interrupt priority or the plic threshold register. fn into(self) -> u32 { match self { - Priority::Never => 0, + Priority::P0 => 0, Priority::P1 => 1, Priority::P2 => 2, Priority::P3 => 3, @@ -38,6 +44,7 @@ impl Into for Priority { } } +/// Plic interface pub struct Plic<'a>(pub &'a PLIC); impl<'a> Clone for Plic<'a> { @@ -49,78 +56,127 @@ impl<'a> Clone for Plic<'a> { impl<'a> Copy for Plic<'a> { } +/// Represents a register offset and mask for +/// accessing an individual bit in a register +/// file. +struct Loc { + offset: usize, + mask: u32, +} + +impl Loc { + /// Computes the location of an interrupt. + //#[inline] + pub fn from(intr: Interrupt) -> Self { + // offset = nr / 32 + // bit = nr % 32 + // 32 = 2 ^ 5 + let nr = intr.nr(); + let bit = nr & 31; + Self { + offset: (nr >> 5) as usize, + mask: 1 << bit + } + } + + /// Checks if bit is set. + //#[inline] + pub fn is_set(&self, bits: u32) -> bool { + bits & self.mask == self.mask + } +} + impl<'a> Plic<'a> { - /*pub fn init(&self) { + /// Initializes PLIC controller by resetting all + /// enable bits to 0 and enables MachineExternal + /// interrupts. + pub fn init(&self) { for reg in self.0.enable.iter() { unsafe { reg.write(|w| w.bits(0)); } } + self.set_threshold(Priority::P0); + self.enable_mext(); + } - //interrupt!(MachineExternal, plic::plic_handler()); - }*/ - - pub fn enable_mexternal(&self) { + /// Enable MachineExternal interrupts. + #[inline] + pub fn enable_mext(&self) { csr::mie.set(|w| w.mext()); } - pub fn clear_mexternal(&self) { + /// Disable MachineExternal interrupts. + #[inline] + pub fn disable_mext(&self) { csr::mie.clear(|w| w.mext()); } + /// Returns true when plic::Interrupt is pending. pub fn is_pending(&self, intr: Interrupt) -> bool { - let mask = 1 << (intr.nr() % 32); - let pending = self.0.pending[(intr.nr() / 32) as usize].read(); - pending.bits() & mask == mask + let loc = Loc::from(intr); + let pending = self.0.pending[loc.offset].read(); + loc.is_set(pending.bits()) } + /// Returns true when plic::Interrupt is enabled. pub fn is_enabled(&self, intr: Interrupt) -> bool { - let mask = 1 << (intr.nr() % 32); - let enable = self.0.enable[(intr.nr() / 32) as usize].read(); - enable.bits() & mask == mask + let loc = Loc::from(intr); + let enable = self.0.enable[loc.offset].read(); + loc.is_set(enable.bits()) } + /// Enables plic::Interrupt. pub fn enable(&self, intr: Interrupt) { - let mask = 1 << (intr.nr() % 32); + let loc = Loc::from(intr); unsafe { - self.0.enable[(intr.nr() / 32) as usize] - .modify(|r, w| w.bits(r.bits() | mask)); + self.0.enable[loc.offset] + .modify(|r, w| w.bits(r.bits() | loc.mask)); } } + /// Disables plic::Interrupt. pub fn disable(&self, intr: Interrupt) { - let mask = 1 << (intr.nr() % 32); + let loc = Loc::from(intr); unsafe { - self.0.enable[(intr.nr() / 32) as usize] - .modify(|r, w| w.bits(r.bits() & !mask)); + self.0.enable[loc.offset] + .modify(|r, w| w.bits(r.bits() & !loc.mask)); } } + /// Claims the plic::Interrupt with the highest priority. pub fn claim(&self) -> Interrupt { Interrupt::from(self.0.claim.read().bits() as u8) } + /// Notifies the PLIC that the claimed plic::Interrupt is + /// complete. pub fn complete(&self, intr: Interrupt) { unsafe { self.0.claim.write(|w| w.bits(intr.nr() as u32)); } } + /// Returns the plic::Priority of a plic::Interrupt. pub fn get_priority(&self, intr: Interrupt) -> Priority { - Priority::from(self.0.priority[(intr.nr() - 1) as usize].read().bits()) + Priority::from(self.0.priority[intr.nr() as usize].read().bits()) } + /// Sets the plic::Priority of a plic::Interrupt. pub fn set_priority(&self, intr: Interrupt, prio: Priority) { unsafe { - self.0.priority[(intr.nr() - 1) as usize] + self.0.priority[intr.nr() as usize] .write(|w| w.bits(prio.into())); } } + /// Returns the PLIC threshold priority. pub fn get_threshold(&self) -> Priority { Priority::from(self.0.threshold.read().bits()) } + /// Sets the PLIC threshold priority. This disables all + /// interrupts with a lower plic::Priority. pub fn set_threshold(&self, prio: Priority) { unsafe { self.0.threshold.write(|w| w.bits(prio.into())); From 77c731228765f3e9441861bdbba97bbb50e8eb04 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 22 Nov 2017 18:16:23 +0100 Subject: [PATCH 009/315] Add rtc driver. --- examples/blinky_plic.rs | 12 +++- src/lib.rs | 2 + src/rtc.rs | 126 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/rtc.rs diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs index fb75591..ed11cb2 100644 --- a/examples/blinky_plic.rs +++ b/examples/blinky_plic.rs @@ -24,8 +24,16 @@ fn main() { let serial = Serial(p.UART0); let mut stdout = Port(&serial); - writeln!(stdout, "RTC interrupt is set {}", plic.is_enabled(Interrupt::RTC)).unwrap(); - writeln!(stdout, "RTC interrupt nr is {}", Interrupt::RTC.nr()).unwrap(); + writeln!(stdout, "External interrupts enabled: {}", + csr::mstatus.read().meie()).unwrap(); + writeln!(stdout, "PLIC threshold priority: {}", + plic.get_threshold()).unwrap(); + writeln!(stdout, "RTC interrupt number: {}", + Interrupt::RTC.nr()).unwrap(); + writeln!(stdout, "RTC interrupt enabled: {}", + plic.is_enabled(Interrupt::RTC)).unwrap(); + writeln!(stdout, "RTC interrupt priority: {}", + plic.get_priority(Interrupt::RTC)).unwrap(); unsafe { interrupt::enable(); diff --git a/src/lib.rs b/src/lib.rs index 13c3c23..228a96b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub mod gpio; pub mod led; pub mod plic; pub mod pwm; +pub mod rtc; pub mod serial; pub mod time; @@ -32,6 +33,7 @@ pub use clint::Clint; pub use led::{Red, Green, Blue}; pub use plic::{Priority, Interrupt, Plic}; pub use pwm::{Align, Channel, Pwm}; +pub use rtc::{Rtc, RtcConf}; pub use serial::{Serial, Port}; pub use time::UExt; diff --git a/src/rtc.rs b/src/rtc.rs new file mode 100644 index 0000000..88dfa14 --- /dev/null +++ b/src/rtc.rs @@ -0,0 +1,126 @@ +//! RTC +use e310x::{PLIC, RTC}; +use plic::{Plic, Interrupt, Priority}; + +/// Rtc configuration +pub struct RtcConf { + enalways: bool, + scale: u8, + counter: u64, + cmp: u32, + priority: Priority, +} + +impl RtcConf { + pub fn new() -> Self { + Self { + enalways: true, + scale: 0, + counter: 0, + cmp: 0, + priority: Priority::P1, + } + } + + pub fn set_enalways(&mut self, en: bool) -> &mut Self { + self.enalways = en; + self + } + + pub fn set_scale(&mut self, scale: u8) -> &mut Self { + assert!(scale < 16); + self.scale = scale; + self + } + + pub fn set_counter(&mut self, counter: u64) -> &mut Self { + assert!(counter < (1 << 49) - 1); + self.counter = counter; + self + } + pub fn set_cmp(&mut self, cmp: u32) -> &mut Self { + self.cmp = cmp; + self + } + + pub fn set_priority(&mut self, prio: Priority) -> &mut Self { + self.priority = prio; + self + } + + pub fn end(&self, rtc: &RTC) { + //let plic = Plic(plic); + let rtc = Rtc(rtc); + + //plic.disable(Interrupt::RTC); + + unsafe { + rtc.0.rtccfg.modify(|_, w| { + w.enalways().bit(self.enalways) + .scale().bits(self.scale) + }); + + rtc.0.rtchi.write(|w| w.bits((self.counter >> 32) as u32)); + rtc.0.rtclo.write(|w| w.bits(self.counter as u32)); + rtc.0.rtccmp.write(|w| w.bits(self.cmp)); + } + + //plic.set_priority(Interrupt::RTC, self.priority); + //plic.enable(Interrupt::RTC); + } +} + + +/// Rtc interface +pub struct Rtc<'a>(pub &'a RTC); + +impl<'a> Clone for Rtc<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Copy for Rtc<'a> {} + +impl<'a> ::hal::Timer for Rtc<'a> { + type Time = ::aonclk::Ticks; + + fn get_timeout(&self) -> ::aonclk::Ticks { + ::aonclk::Ticks(self.0.rtccmp.read().bits()) + } + + fn pause(&self) { + self.0.rtccfg.modify(|_, w| w.enalways().bit(false)); + } + + fn restart(&self) { + unsafe { + self.0.rtchi.write(|w| w.bits(0)); + self.0.rtclo.write(|w| w.bits(0)); + } + self.0.rtccfg.modify(|_, w| w.enalways().bit(true)); + } + + fn resume(&self) { + self.0.rtccfg.modify(|_, w| w.enalways().bit(true)); + } + + fn set_timeout(&self, timeout: T) + where + T: Into<::aonclk::Ticks>, + { + self.pause(); + unsafe { + self.0.rtccmp.write(|w| w.bits(1)); + } + self.restart(); + } + + fn wait(&self) -> ::nb::Result<(), !> { + if self.0.rtccfg.read().cmpip().bit() { + Ok(()) + } else { + Err(::nb::Error::WouldBlock) + } + } +} From 00e8b7da020367739888ca046921b64496e9e117 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 22 Nov 2017 18:17:00 +0100 Subject: [PATCH 010/315] Add link to documentation. --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 46f873d..6d5dfb2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ +[![crates.io](https://img.shields.io/crates/d/hifive.svg)](https://crates.io/crates/hifive) +[![crates.io](https://img.shields.io/crates/v/hifive.svg)](https://crates.io/crates/hifive) + # `hifive` > Board support crate for hifive and lofive boards. -# License +## [Documentation](https://docs.rs/crate/hifive) + +## License Copyright 2017 David Craven Permission to use, copy, modify, and/or distribute this software for any purpose From 39c6cccf78807f805649a9a4d5aead47955967aa Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 22 Nov 2017 18:17:44 +0100 Subject: [PATCH 011/315] Extend panicking example. --- examples/panicking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/panicking.rs b/examples/panicking.rs index 480534f..3043756 100644 --- a/examples/panicking.rs +++ b/examples/panicking.rs @@ -2,12 +2,12 @@ extern crate hifive; -fn three() { +fn three(_1: u32, _2: u32) { panic!() } fn two() { - three(); + three(0x0123_4567, 0x1234_5678); } fn one() { From d03041d2fd3d9e76265a9e927c9907cc75f1b7de Mon Sep 17 00:00:00 2001 From: David Craven Date: Thu, 23 Nov 2017 14:38:17 +0100 Subject: [PATCH 012/315] Add docstrings. --- src/clint.rs | 15 ++++++++++++--- src/gpio.rs | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/clint.rs b/src/clint.rs index e0d905d..c2b86e0 100644 --- a/src/clint.rs +++ b/src/clint.rs @@ -15,6 +15,7 @@ impl<'a> Copy for Clint<'a> { } impl<'a> Clint<'a> { + /// Read mtime register. pub fn get_mtime(&self) -> ::aonclk::Ticks { loop { let hi = self.0.mtimeh.read().bits(); @@ -25,6 +26,7 @@ impl<'a> Clint<'a> { } } + /// Write mtime register. pub fn set_mtime(&self, time: ::aonclk::Ticks) { unsafe { self.0.mtimeh.write(|w| w.bits(time.into_hi())); @@ -32,12 +34,14 @@ impl<'a> Clint<'a> { } } + /// Read mtimecmp register. pub fn get_mtimecmp(&self) -> ::aonclk::Ticks { let hi = self.0.mtimecmph.read().bits() as u64; let lo = self.0.mtimecmp.read().bits() as u64; ::aonclk::Ticks(hi << 32 | lo) } + /// Write mtimecmp register. pub fn set_mtimecmp(&self, time: ::aonclk::Ticks) { unsafe { self.0.mtimecmph.write(|w| w.bits(time.into_hi())); @@ -45,6 +49,7 @@ impl<'a> Clint<'a> { } } + /// Read mcycle register. pub fn get_mcycle(&self) -> ::coreclk::Ticks { loop { let hi = csr::mcycleh.read().bits(); @@ -55,11 +60,13 @@ impl<'a> Clint<'a> { } } + /// Write mcycle register. pub fn set_mcycle(&self, cycle: ::coreclk::Ticks) { csr::mcycleh.write(|w| w.bits(cycle.into_hi())); csr::mcycle.write(|w| w.bits(cycle.into())); } + /// Read minstret register. pub fn get_minstret(&self) -> u64 { loop { let hi = csr::minstreth.read().bits(); @@ -70,27 +77,29 @@ impl<'a> Clint<'a> { } } + /// Write minstret register. pub fn set_minstret(&self, instret: u64) { csr::minstreth.write(|w| w.bits((instret >> 32) as u32)); csr::minstret.write(|w| w.bits(instret as u32)); } - /// Enable the Machine-Timer interrupt + /// Enable Machine-Timer interrupt. pub fn enable_mtimer(&self) { csr::mie.set(|w| w.mtimer()); } - /// Disable the Machine-Timer interrupt + /// Disable Machine-Timer interrupt. pub fn disable_mtimer(&self) { csr::mie.clear(|w| w.mtimer()); } - // Is Machine-Timer interrupt pending + /// Check if the Machine-Timer is interrupt pending. pub fn is_mtimer_pending(&self) -> bool { csr::mip.read().mtimer() } + /// Measure the coreclk frequency by counting the number of aonclk ticks. pub fn measure_coreclk(&self, min_ticks: ::aonclk::Ticks) -> u32 { interrupt::free(|_| { let clint = self.0; diff --git a/src/gpio.rs b/src/gpio.rs index f5eb655..ba89a04 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -3,6 +3,7 @@ use core::ops::Deref; use e310x::gpio0; +/// Enumeration of possible pin configurations. pub enum PinConfig { Input, InputPullup, @@ -12,6 +13,7 @@ pub enum PinConfig { IoFn1, } +/// Enumeration of pin interrupts. pub enum PinInterrupt { Rise, Fall, From acdbedb0bb462c80d527dd68fe052c068f296304 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 25 Nov 2017 10:28:23 +0100 Subject: [PATCH 013/315] Update example. --- examples/blinky_plic.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs index ed11cb2..a23c131 100644 --- a/examples/blinky_plic.rs +++ b/examples/blinky_plic.rs @@ -25,27 +25,28 @@ fn main() { let serial = Serial(p.UART0); let mut stdout = Port(&serial); writeln!(stdout, "External interrupts enabled: {}", - csr::mstatus.read().meie()).unwrap(); + csr::mie.read().mext()).unwrap(); + let threshold: u32 = plic.get_threshold().into(); writeln!(stdout, "PLIC threshold priority: {}", - plic.get_threshold()).unwrap(); + threshold).unwrap(); writeln!(stdout, "RTC interrupt number: {}", Interrupt::RTC.nr()).unwrap(); writeln!(stdout, "RTC interrupt enabled: {}", plic.is_enabled(Interrupt::RTC)).unwrap(); + let priority: u32 = plic.get_priority(Interrupt::RTC).into(); writeln!(stdout, "RTC interrupt priority: {}", - plic.get_priority(Interrupt::RTC)).unwrap(); + priority).unwrap(); unsafe { interrupt::enable(); } - - loop {} } #[no_mangle] pub fn plic_trap_handler(p: &Peripherals, intr: &Interrupt) { match *intr { Interrupt::RTC => { + Rtc(p.RTC).restart(); Blue::toggle(p.GPIO0); }, _ => {}, From 1756937351f3338d8d40edfa0379d9ad24efb283 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 25 Nov 2017 10:29:01 +0100 Subject: [PATCH 014/315] Fix priority register offset. --- src/plic.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plic.rs b/src/plic.rs index b2a4f31..97226d0 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -28,7 +28,7 @@ impl Priority { } impl Into for Priority { - /// Returns the numeric priority for wirting to a + /// Returns the numeric priority for writing to a /// interrupt priority or the plic threshold register. fn into(self) -> u32 { match self { @@ -93,7 +93,8 @@ impl<'a> Plic<'a> { pub fn init(&self) { for reg in self.0.enable.iter() { unsafe { - reg.write(|w| w.bits(0)); + // bug somewhere enabling interrupts + reg.write(|w| w.bits(0xFFFF_FFFF)); } } self.set_threshold(Priority::P0); @@ -159,13 +160,15 @@ impl<'a> Plic<'a> { /// Returns the plic::Priority of a plic::Interrupt. pub fn get_priority(&self, intr: Interrupt) -> Priority { - Priority::from(self.0.priority[intr.nr() as usize].read().bits()) + // Priority array is offset by one. + Priority::from(self.0.priority[intr.nr() as usize - 1].read().bits()) } /// Sets the plic::Priority of a plic::Interrupt. pub fn set_priority(&self, intr: Interrupt, prio: Priority) { + // Priority array is offset by one. unsafe { - self.0.priority[intr.nr() as usize] + self.0.priority[intr.nr() as usize - 1] .write(|w| w.bits(prio.into())); } } From df5b87be333ea612fe72edfed2d783018f12ecf4 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 25 Nov 2017 10:29:18 +0100 Subject: [PATCH 015/315] Cleanup rtc driver. --- src/rtc.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/rtc.rs b/src/rtc.rs index 88dfa14..cc8b41d 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -1,6 +1,5 @@ //! RTC -use e310x::{PLIC, RTC}; -use plic::{Plic, Interrupt, Priority}; +use e310x::RTC; /// Rtc configuration pub struct RtcConf { @@ -8,7 +7,6 @@ pub struct RtcConf { scale: u8, counter: u64, cmp: u32, - priority: Priority, } impl RtcConf { @@ -18,7 +16,6 @@ impl RtcConf { scale: 0, counter: 0, cmp: 0, - priority: Priority::P1, } } @@ -43,17 +40,8 @@ impl RtcConf { self } - pub fn set_priority(&mut self, prio: Priority) -> &mut Self { - self.priority = prio; - self - } - pub fn end(&self, rtc: &RTC) { - //let plic = Plic(plic); let rtc = Rtc(rtc); - - //plic.disable(Interrupt::RTC); - unsafe { rtc.0.rtccfg.modify(|_, w| { w.enalways().bit(self.enalways) @@ -64,9 +52,6 @@ impl RtcConf { rtc.0.rtclo.write(|w| w.bits(self.counter as u32)); rtc.0.rtccmp.write(|w| w.bits(self.cmp)); } - - //plic.set_priority(Interrupt::RTC, self.priority); - //plic.enable(Interrupt::RTC); } } @@ -111,7 +96,7 @@ impl<'a> ::hal::Timer for Rtc<'a> { { self.pause(); unsafe { - self.0.rtccmp.write(|w| w.bits(1)); + self.0.rtccmp.write(|w| w.bits(timeout.into().into())); } self.restart(); } From 90d1bc4edc6502e668dba4c7c26ea68d9e7a6407 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 25 Nov 2017 12:48:32 +0100 Subject: [PATCH 016/315] Export PinConfig and PinInterrupt. --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 228a96b..ce04098 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ use riscv::interrupt::Nr; pub use hal::prelude; pub use riscv::{csr, interrupt}; pub use e310x::Peripherals; +pub use gpio::{PinConfig, PinInterrupt}; pub use clint::Clint; pub use led::{Red, Green, Blue}; pub use plic::{Priority, Interrupt, Plic}; From 43b09945dbffa80e0d3d3c03ea3126aac23cb817 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 2 Dec 2017 13:36:32 +0100 Subject: [PATCH 017/315] Implement clear_pending. --- src/gpio.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/gpio.rs b/src/gpio.rs index ba89a04..dd9ff2e 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -132,6 +132,22 @@ macro_rules! pin { }; } + pub fn clear_pending(gpio: &T, intr: PinInterrupt) + where + T: Deref, + { + match intr { + PinInterrupt::Rise => + gpio.rise_ip.write(|w| w.$pinx().bit(true)), + PinInterrupt::Fall => + gpio.fall_ip.write(|w| w.$pinx().bit(true)), + PinInterrupt::High => + gpio.high_ip.write(|w| w.$pinx().bit(true)), + PinInterrupt::Low => + gpio.low_ip.write(|w| w.$pinx().bit(true)), + } + } + pub fn is_interrupt_pending(gpio: &T, intr: PinInterrupt) -> bool where T: Deref, From e5a1bfc4faa17bbd631c4199b792be98c29b97ea Mon Sep 17 00:00:00 2001 From: David Craven Date: Fri, 23 Feb 2018 11:27:51 +0100 Subject: [PATCH 018/315] Move examples to workspace. --- .cargo/config | 6 --- .gdbinit | 24 ------------ Cargo.toml | 17 ++------- Makefile | 51 ------------------------- Xargo.toml | 7 ---- build.rs | 7 ---- examples/blinky_clint.rs | 24 ------------ examples/blinky_delay.rs | 34 ----------------- examples/blinky_plic.rs | 54 --------------------------- examples/blinky_pwm.rs | 81 ---------------------------------------- examples/hello_world.rs | 13 ------- examples/panicking.rs | 19 ---------- examples/pll.rs | 27 -------------- openocd.cfg | 34 ----------------- 14 files changed, 4 insertions(+), 394 deletions(-) delete mode 100644 .cargo/config delete mode 100644 .gdbinit delete mode 100644 Makefile delete mode 100644 Xargo.toml delete mode 100644 examples/blinky_clint.rs delete mode 100644 examples/blinky_delay.rs delete mode 100644 examples/blinky_plic.rs delete mode 100644 examples/blinky_pwm.rs delete mode 100644 examples/hello_world.rs delete mode 100644 examples/panicking.rs delete mode 100644 examples/pll.rs delete mode 100644 openocd.cfg diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index a4229f7..0000000 --- a/.cargo/config +++ /dev/null @@ -1,6 +0,0 @@ -[target.riscv32-unknown-none] -runner = 'riscv32-unknown-elf-gdb' -rustflags = [ - "-C", "link-arg=-Tlink.x", - "-C", "linker=riscv32-unknown-elf-ld", -] \ No newline at end of file diff --git a/.gdbinit b/.gdbinit deleted file mode 100644 index b99fc56..0000000 --- a/.gdbinit +++ /dev/null @@ -1,24 +0,0 @@ -set remotetimeout 240 -target extended-remote localhost:3333 - -define upload - monitor reset halt - monitor flash protect 0 64 last off - load - monitor flash protect 0 64 last on - continue -end -document upload -Upload program to hifive board -end - -# Load Rust's GDB pretty printers -python -import os; -import sys; -path = os.environ['TOOLCHAIN'] + '/lib/rustlib/etc' -sys.path.append(path) - -gdb.execute('directory %s' % path) -gdb.execute('add-auto-load-safe-path %s' % path) -end diff --git a/Cargo.toml b/Cargo.toml index 29d8477..9e9851d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,16 +15,7 @@ rev = "7d904f515d15fd5fe7ea34e18820ea83e2651fa2" [dependencies.nb] git = "https://github.com/japaric/nb" -[dependencies.riscv] -git = "https://github.com/dvc94ch/riscv" - -[dependencies.riscv-rt] -git = "https://github.com/dvc94ch/riscv-rt" - -[dependencies.e310x] -features = ["rt"] -git = "https://github.com/dvc94ch/e310x" - -[profile.release] -debug = true -lto = true \ No newline at end of file +[dependencies] +riscv = { path = "../riscv" } +riscv-rt = { path = "../riscv-rt" } +e310x = { path = "../e310x", features = ["rt"] } diff --git a/Makefile b/Makefile deleted file mode 100644 index 027d085..0000000 --- a/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -# Examples (uncomment one) -#EXAMPLE := blinky_delay -#EXAMPLE := blinky_clint -#EXAMPLE := blinky_pwm -#EXAMPLE := blinky_plic -#EXAMPLE := hello_world -#EXAMPLE := panicking -#EXAMPLE := pll - -# Board crate (uncomment one) -BOARD := hifive - -TARGET := riscv32-unknown-none -TARGET_DIR := $(abspath ./target/$(TARGET)/debug) -EXAMPLE_DIR := $(TARGET_DIR)/examples -EXAMPLE_BIN := $(EXAMPLE_DIR)/$(EXAMPLE) -OPENOCD_CFG := $(wildcard $(TARGET_DIR)/build/$(BOARD)-*/out/openocd.cfg) - -build: - xargo build --examples --target $(TARGET) $(ARGS) - -test: - xargo test --all --target $(TARGET) $(ARGS) - -clean: - xargo clean $(ARGS) - -readelf: - llvm-readelf -a -h -s -r -symbols $(EXAMPLE_BIN) $(ARGS) - -objdump: - llvm-objdump -d -S $(EXAMPLE_BIN) $(ARGS) - -size: - llvm-size $(EXAMPLE_BIN) $(ARGS) - -# .gdbinit adds a upload command to gdb -gdb: - riscv32-unknown-elf-gdb $(EXAMPLE_BIN) $(ARGS) - -openocd: - openocd -f $(OPENOCD_CFG) $(ARGS) - -upload: - openocd -f $(OPENOCD_CFG) \ - -c "flash protect 0 64 last off; program ${EXAMPLE_BIN}; resume 0x20400000; exit" - -framedump: - riscv32-unknown-elf-readelf --debug-dump=frames $(EXAMPLE_BIN) $(ARGS) - -.PHONY: build clean readelf objdump framedump size gdb openocd spike diff --git a/Xargo.toml b/Xargo.toml deleted file mode 100644 index 001a159..0000000 --- a/Xargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[dependencies] -core = {} -alloc = {} - -[dependencies.compiler_builtins] -features = ["mem"] -stage = 1 diff --git a/build.rs b/build.rs index ab3a5b6..dedafe9 100644 --- a/build.rs +++ b/build.rs @@ -13,12 +13,5 @@ fn main() { println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rerun-if-changed=memory.x"); - // Copy openocd.cfg to output directory - File::create(out.join("openocd.cfg")) - .unwrap() - .write_all(include_bytes!("openocd.cfg")) - .unwrap(); - println!("cargo:rerun-if-changed=openocd.cfg"); - println!("cargo:rerun-if-changed=build.rs"); } diff --git a/examples/blinky_clint.rs b/examples/blinky_clint.rs deleted file mode 100644 index 3798ccf..0000000 --- a/examples/blinky_clint.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![no_std] - -extern crate hifive; - -use hifive::prelude::*; -use hifive::{interrupt, led, Blue, Clint, Peripherals, UExt}; - -fn main() { - let peripherals = hifive::init(115_200); - led::init(peripherals.GPIO0); - - let timer = Clint(peripherals.CLINT); - timer.set_timeout(1.s()); - - unsafe { - interrupt::enable(); - } -} - -#[no_mangle] -pub fn mtimer_trap_handler(p: &Peripherals) { - Clint(p.CLINT).restart(); - Blue::toggle(p.GPIO0); -} diff --git a/examples/blinky_delay.rs b/examples/blinky_delay.rs deleted file mode 100644 index 3f40f33..0000000 --- a/examples/blinky_delay.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] - -#[macro_use] -extern crate nb; -extern crate hifive; - -use hifive::prelude::*; -use hifive::{led, Red, Green, Blue, Clint, UExt}; - -fn delay(clint: &Clint) { - block!(clint.wait()).unwrap(); - clint.restart(); -} - -fn main() { - let peripherals = hifive::init(115_200); - led::init(peripherals.GPIO0); - - let clint = Clint(peripherals.CLINT); - clint.set_timeout(500.ms()); - - let gpio = peripherals.GPIO0; - loop { - Red::on(gpio); - delay(&clint); - Red::off(gpio); - Green::on(gpio); - delay(&clint); - Green::off(gpio); - Blue::on(gpio); - delay(&clint); - Blue::off(gpio); - } -} diff --git a/examples/blinky_plic.rs b/examples/blinky_plic.rs deleted file mode 100644 index a23c131..0000000 --- a/examples/blinky_plic.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![no_std] - -extern crate hifive; - -use core::fmt::Write; -use hifive::*; -use hifive::prelude::*; -use hifive::interrupt::Nr; - -fn main() { - let p = hifive::init(115_200); - led::init(p.GPIO0); - - Red::on(p.GPIO0); - - let plic = Plic(p.PLIC); - plic.init(); - - RtcConf::new().end(p.RTC); - Rtc(p.RTC).set_timeout(500.ms()); - - plic.set_priority(Interrupt::RTC, Priority::P7); - plic.enable(Interrupt::RTC); - - let serial = Serial(p.UART0); - let mut stdout = Port(&serial); - writeln!(stdout, "External interrupts enabled: {}", - csr::mie.read().mext()).unwrap(); - let threshold: u32 = plic.get_threshold().into(); - writeln!(stdout, "PLIC threshold priority: {}", - threshold).unwrap(); - writeln!(stdout, "RTC interrupt number: {}", - Interrupt::RTC.nr()).unwrap(); - writeln!(stdout, "RTC interrupt enabled: {}", - plic.is_enabled(Interrupt::RTC)).unwrap(); - let priority: u32 = plic.get_priority(Interrupt::RTC).into(); - writeln!(stdout, "RTC interrupt priority: {}", - priority).unwrap(); - - unsafe { - interrupt::enable(); - } -} - -#[no_mangle] -pub fn plic_trap_handler(p: &Peripherals, intr: &Interrupt) { - match *intr { - Interrupt::RTC => { - Rtc(p.RTC).restart(); - Blue::toggle(p.GPIO0); - }, - _ => {}, - } -} diff --git a/examples/blinky_pwm.rs b/examples/blinky_pwm.rs deleted file mode 100644 index bf0d14a..0000000 --- a/examples/blinky_pwm.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![no_std] - -extern crate hifive; - -use hifive::{Channel, Align, Pwm}; - -const RED: Channel = Channel::_3; -const GREEN: Channel = Channel::_1; -const BLUE: Channel = Channel::_2; - -/* -struct Color { - red: u8, - green: u8, - blue: u8, -} - -impl Color { - pub fn from(red: u8, green: u8, blue: u8) -> Self { - Color { red, green, blue } - } -} - -fn set_color(pwm: Pwm, color: Color) { - pwm.set_cmp(RED, u16::max_value() / 255 * color.red as u16); - pwm.set_cmp(GREEN, u16::max_value() / 255 * color.green as u16); - pwm.set_cmp(BLUE, u16::max_value() / 255 * color.blue as u16); -} -*/ - -fn main() { - let peripherals = hifive::init(115_200); - let gpio = peripherals.GPIO0; - - //let clint = Clint(peripherals.CLINT); - let pwm = Pwm(peripherals.PWM1); - - pwm.set_cmp(Channel::_0, u16::max_value()); - //pwm.set_period(63); - - pwm.enable(RED, Align::Left, gpio); - pwm.invert(RED, gpio); - pwm.set_cmp(RED, u16::max_value() / 3); - - pwm.enable(GREEN, Align::Center, gpio); - pwm.invert(GREEN, gpio); - pwm.set_cmp(GREEN, u16::max_value() / 2); - - pwm.enable(BLUE, Align::Right, gpio); - pwm.invert(BLUE, gpio); - pwm.set_cmp(BLUE, u16::max_value() / 3 * 2); - - pwm.init(); - - //let delay = 1.s(); - - /*loop { - // Gray - set_color(pwm, Color::from(0x80, 0x80, 0x80)); - clint.set_timeout(delay); - block!(clint.wait()); - // Purple - set_color(pwm, Color::from(0x80, 0x00, 0x80)); - clint.set_timeout(delay); - block!(clint.wait()); - // Maroon - set_color(pwm, Color::from(0x80, 0x00, 0x00)); - clint.set_timeout(delay); - block!(clint.wait()); - }*/ - - //pwm.invert(GREEN, gpio, true); - //pwm.align_center(GREEN); - //pwm.set_cmp(GREEN, u16::max_value() / 2); - - //pwm.align_left(RED); - //pwm.align_right(BLUE); - //pwm.set_cmp(BLUE, u16::max_value() / 3 * 2); - //pwm.set_cmp(BLUE, 0); - //pwm.enable(BLUE, gpio); -} diff --git a/examples/hello_world.rs b/examples/hello_world.rs deleted file mode 100644 index 9f5678d..0000000 --- a/examples/hello_world.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![no_std] - -extern crate hifive; - -use core::fmt::Write; -use hifive::{Port, Serial}; - -fn main() { - let peripherals = hifive::init(115_200); - - let serial = Serial(peripherals.UART0); - writeln!(Port(&serial), "hello world!").unwrap(); -} diff --git a/examples/panicking.rs b/examples/panicking.rs deleted file mode 100644 index 3043756..0000000 --- a/examples/panicking.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![no_std] - -extern crate hifive; - -fn three(_1: u32, _2: u32) { - panic!() -} - -fn two() { - three(0x0123_4567, 0x1234_5678); -} - -fn one() { - two(); -} - -fn main() { - one(); -} diff --git a/examples/pll.rs b/examples/pll.rs deleted file mode 100644 index 054efa1..0000000 --- a/examples/pll.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![no_std] - -extern crate hifive; - -use core::fmt::Write; -use hifive::{clock, Clint, Port, Serial}; - -fn main() { - let p = hifive::init(115_200); - - let serial = Serial(p.UART0); - let mut stdout = Port(&serial); - writeln!(stdout, "Setting up PLL").unwrap(); - - let clint = Clint(p.CLINT); - let clock = clock::CoreClock(p.PRCI); - - let freq_calc_default = clock.pll_mult() * 16; - unsafe { clock.use_pll(&clint); } - let freq_calc = clock.pll_mult() * 16; - let freq_measured = clock.measure(&clint) / 1_000_000; - unsafe { clock.use_external(&clint); } - - writeln!(stdout, "Default PLL settings {}MHz", freq_calc_default).unwrap(); - writeln!(stdout, "Measured clock frequency of {}MHz", freq_measured).unwrap(); - writeln!(stdout, "Computed clock frequency of {}MHz", freq_calc).unwrap(); -} diff --git a/openocd.cfg b/openocd.cfg deleted file mode 100644 index 40e7849..0000000 --- a/openocd.cfg +++ /dev/null @@ -1,34 +0,0 @@ -adapter_khz 10000 - -interface ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 - -ftdi_layout_init 0x0008 0x001b -ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 - -#Reset Stretcher logic on FE310 is ~1 second long -#This doesn't apply if you use -# ftdi_set_signal, but still good to document -#adapter_nsrst_delay 1500 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 - -flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME -init -#reset -- This type of reset is not implemented yet -if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z - #Wait for the reset stretcher - #It will work without this, but - #will incur lots of delays for later commands. - sleep 1500 -} -halt -#flash protect 0 64 last off \ No newline at end of file From 9550d4ea044741a15d73cb442be4f075315916b9 Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 27 Feb 2018 17:41:07 +0100 Subject: [PATCH 019/315] Disable init message. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ce04098..20f29e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,6 @@ pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { // Initialize UART0 let serial = Serial(peripherals.UART0); serial.init(baud_rate.hz().invert(), peripherals.GPIO0); - writeln!(Port(&serial), "Initialized hifive board").unwrap(); peripherals } From 247d1820f5679d773f0a94c441d23b104e2be303 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 28 Feb 2018 20:07:05 +0100 Subject: [PATCH 020/315] Add interrupt and exception trap handler. --- src/lib.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 20f29e2..2cd699b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ extern crate embedded_hal as hal; #[macro_use] extern crate nb; -extern crate riscv; +pub extern crate riscv; pub extern crate e310x; pub mod clint; @@ -23,9 +23,6 @@ pub mod rtc; pub mod serial; pub mod time; -use core::fmt::Write; -use riscv::interrupt::Nr; - pub use hal::prelude; pub use riscv::{csr, interrupt}; pub use e310x::Peripherals; @@ -66,33 +63,30 @@ pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { pub fn trap_handler(trap: riscv::csr::Trap) { use riscv::csr::{Trap, Interrupt}; - let peripherals = unsafe { e310x::Peripherals::all() }; - let serial = Serial(peripherals.UART0); + let p = unsafe { e310x::Peripherals::all() }; match trap { Trap::Interrupt(x) => { match x { Interrupt::MachineTimer => { - writeln!(Port(&serial), "MachineTimer").unwrap(); - mtimer_trap_handler(&peripherals); + mtimer_trap_handler(&p); }, Interrupt::MachineExternal => { - let plic = Plic(peripherals.PLIC); + let plic = Plic(p.PLIC); let intr = plic.claim(); - writeln!(Port(&serial), "ExternalInterrupt {}", intr.nr()).unwrap(); - plic_trap_handler(&peripherals, &intr); + plic_trap_handler(&p, &intr); plic.complete(intr); } x => { - writeln!(Port(&serial), "Interrupt {}", x as u32).unwrap(); + interrupt_trap_handler(&p, x); }, } }, Trap::Exception(x) => { let mepc = csr::mepc.read().bits(); - writeln!(Port(&serial), "Exception {} at 0x{:x}", x as u32, mepc).unwrap(); + exception_trap_handler(&p, x, mepc); }, } } @@ -107,6 +101,18 @@ pub fn mtimer_trap_handler(_: &e310x::Peripherals) {} #[linkage = "weak"] pub fn plic_trap_handler(_: &e310x::Peripherals, _: &Interrupt) {} +/// Default Interrupt Trap Handler +/// +/// Only called when interrupt is not a MachineTimer or +/// MachineExternal interrupt. +#[no_mangle] +#[linkage = "weak"] +pub fn interrupt_trap_handler(_: &e310x::Peripherals, _: riscv::csr::Interrupt) {} + +/// Default Exception Trap Handler +#[no_mangle] +#[linkage = "weak"] +pub fn exception_trap_handler(_: &e310x::Peripherals, _: riscv::csr::Exception, _: u32) {} macro_rules! ticks_impl { ($n:ident, $t:ty, $f:expr) => { From cf0b038da450c9730c1ff5a9091a07b96b812cbb Mon Sep 17 00:00:00 2001 From: David Craven Date: Thu, 1 Mar 2018 12:03:11 +0100 Subject: [PATCH 021/315] Update to svd2rust 0.12.0 --- src/lib.rs | 24 +++--------------------- src/plic.rs | 14 ++++++++------ 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2cd699b..d1c93d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![feature(lang_items)] #![feature(linkage)] #![feature(never_type)] +#![feature(try_from)] #![feature(used)] extern crate embedded_hal as hal; @@ -35,25 +36,6 @@ pub use rtc::{Rtc, RtcConf}; pub use serial::{Serial, Port}; pub use time::UExt; -/// Initializes the clocks, plic and uart0. Returns Peripherals -/// for application specific initialization. -pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { - let peripherals = unsafe { e310x::Peripherals::all() }; - - // Setup clocks - let clint = Clint(peripherals.CLINT); - let aon_clock = clock::AonClock(peripherals.AONCLK); - unsafe { aon_clock.use_external(); } - let clock = clock::CoreClock(peripherals.PRCI); - unsafe { clock.use_external(&clint); } - - // Initialize UART0 - let serial = Serial(peripherals.UART0); - serial.init(baud_rate.hz().invert(), peripherals.GPIO0); - - peripherals -} - /// Default trap handler /// /// Prints trap cause and calls mtimer_trap_handler or plic_trap_handler if @@ -63,7 +45,7 @@ pub fn init<'a>(baud_rate: u32) -> e310x::Peripherals<'a> { pub fn trap_handler(trap: riscv::csr::Trap) { use riscv::csr::{Trap, Interrupt}; - let p = unsafe { e310x::Peripherals::all() }; + let p = e310x::Peripherals::take().unwrap(); match trap { Trap::Interrupt(x) => { @@ -72,7 +54,7 @@ pub fn trap_handler(trap: riscv::csr::Trap) { mtimer_trap_handler(&p); }, Interrupt::MachineExternal => { - let plic = Plic(p.PLIC); + let plic = Plic(&p.PLIC); let intr = plic.claim(); plic_trap_handler(&p, &intr); diff --git a/src/plic.rs b/src/plic.rs index 97226d0..91f3ba6 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -1,3 +1,4 @@ +use core::convert::TryFrom; use riscv::csr; use riscv::interrupt::Nr; use e310x::PLIC; @@ -147,7 +148,7 @@ impl<'a> Plic<'a> { /// Claims the plic::Interrupt with the highest priority. pub fn claim(&self) -> Interrupt { - Interrupt::from(self.0.claim.read().bits() as u8) + Interrupt::try_from(self.0.claim.read().bits() as u8).unwrap() } /// Notifies the PLIC that the claimed plic::Interrupt is @@ -159,18 +160,19 @@ impl<'a> Plic<'a> { } /// Returns the plic::Priority of a plic::Interrupt. - pub fn get_priority(&self, intr: Interrupt) -> Priority { + pub fn get_priority(&self, _intr: Interrupt) -> Priority { // Priority array is offset by one. - Priority::from(self.0.priority[intr.nr() as usize - 1].read().bits()) + Priority::from(0) + //Priority::from(self.0.priority[intr.nr() as usize - 1].read().bits()) } /// Sets the plic::Priority of a plic::Interrupt. - pub fn set_priority(&self, intr: Interrupt, prio: Priority) { + pub fn set_priority(&self, _intr: Interrupt, _prio: Priority) { // Priority array is offset by one. - unsafe { + /*unsafe { self.0.priority[intr.nr() as usize - 1] .write(|w| w.bits(prio.into())); - } + }*/ } /// Returns the PLIC threshold priority. From 1f62bdbab060e09f26ba67d24632b47c31d1fcdc Mon Sep 17 00:00:00 2001 From: David Craven Date: Fri, 23 Mar 2018 18:42:30 +0100 Subject: [PATCH 022/315] Initial commit. --- .gitignore | 4 ++++ Cargo.toml | 15 +++++++++++++++ README.md | 23 +++++++++++++++++++++++ src/lib.rs | 7 +++++++ 4 files changed, 49 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..becb52e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +Cargo.lock +target/ +core +.gdb_history \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..87b70ca --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "e310x-hal" +version = "0.1.0" +authors = ["David Craven "] +repository = "https://github.com/riscv-rust/e310x-hal" +categories = ["embedded", "hardware-support", "no-std"] +description = "HAL for the E310x family of microcontrollers." +keywords = ["riscv", "e310", "hal"] +license = "ISC" + +[dependencies] +embedded-hal = "0.1.2" +riscv = { path = "../riscv" } +riscv-rt = { path = "../riscv-rt" } +e310x = { path = "../e310x", features = ["rt"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..2002120 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +[![crates.io](https://img.shields.io/crates/d/e310x-hal.svg)](https://crates.io/crates/e310x-hal) +[![crates.io](https://img.shields.io/crates/v/e310x-hal.svg)](https://crates.io/crates/e310x-hal) + +# `e310x-hal` + +> HAL for the E310x family of microcontrollers. + +## [Documentation](https://docs.rs/crate/e310x-hal) + +## License +Copyright 2017 David Craven + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..31e1bb2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} From 2a39d01f713d2074c6c1c378db508ec6dd66ef2f Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 27 Mar 2018 20:20:25 +0200 Subject: [PATCH 023/315] Turn hifive into a bsp crate. --- Cargo.toml | 9 +- build.rs | 17 -- memory.x | 22 --- src/clint.rs | 165 ---------------- src/clock.rs | 165 ---------------- src/gpio.rs | 222 ---------------------- src/led.rs | 42 ---- src/lib.rs | 294 ++++++++++------------------ src/plic.rs | 190 ------------------- src/pwm.rs | 515 -------------------------------------------------- src/rtc.rs | 111 ----------- src/serial.rs | 151 --------------- src/time.rs | 110 ----------- 13 files changed, 104 insertions(+), 1909 deletions(-) delete mode 100644 build.rs delete mode 100644 memory.x delete mode 100644 src/clint.rs delete mode 100644 src/clock.rs delete mode 100644 src/gpio.rs delete mode 100644 src/led.rs delete mode 100644 src/plic.rs delete mode 100644 src/pwm.rs delete mode 100644 src/rtc.rs delete mode 100644 src/serial.rs delete mode 100644 src/time.rs diff --git a/Cargo.toml b/Cargo.toml index 9e9851d..c4b3a34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,7 @@ description = "Board support crate for hifive and lofive boards." keywords = ["riscv", "register", "peripheral"] license = "ISC" -[dependencies.embedded-hal] -git = "https://github.com/japaric/embedded-hal" -rev = "7d904f515d15fd5fe7ea34e18820ea83e2651fa2" - -[dependencies.nb] -git = "https://github.com/japaric/nb" - [dependencies] riscv = { path = "../riscv" } riscv-rt = { path = "../riscv-rt" } -e310x = { path = "../e310x", features = ["rt"] } +e310x-hal = { path = "../e310x-hal", features = ["pll", "hfxosc", "lfaltclk"] } diff --git a/build.rs b/build.rs deleted file mode 100644 index dedafe9..0000000 --- a/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put the linker script somewhere the linker can find it - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=memory.x"); - - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/memory.x b/memory.x deleted file mode 100644 index c991460..0000000 --- a/memory.x +++ /dev/null @@ -1,22 +0,0 @@ -MEMORY -{ -/* NOTE K = KiBi = 1024 bytes */ -/* TODO Adjust these memory regions to match your device memory layout */ -FLASH : ORIGIN = 0x20400000, LENGTH = 512M -RAM : ORIGIN = 0x80000000, LENGTH = 16K -} - -/* This is where the call stack will be allocated. */ -/* The stack is of the full descending type. */ -/* You may want to use this variable to locate the call stack and static -variables in different memory regions. Below is shown the default value */ - -/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ - -/* You can use this symbol to customize the location of the .text section */ -/* If omitted the .text section will be placed right after the .vector_table -section */ -/* This is required only on microcontrollers that store some configuration right -after the vector table */ - -/* _stext = ORIGIN(FLASH); */ diff --git a/src/clint.rs b/src/clint.rs deleted file mode 100644 index c2b86e0..0000000 --- a/src/clint.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Clint - -use riscv::{csr, interrupt}; -use e310x::CLINT; - -pub struct Clint<'a>(pub &'a CLINT); - -impl<'a> Clone for Clint<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Copy for Clint<'a> { -} - -impl<'a> Clint<'a> { - /// Read mtime register. - pub fn get_mtime(&self) -> ::aonclk::Ticks { - loop { - let hi = self.0.mtimeh.read().bits(); - let lo = self.0.mtime.read().bits(); - if hi == self.0.mtimeh.read().bits() { - return ::aonclk::Ticks(((hi as u64) << 32) | lo as u64); - } - } - } - - /// Write mtime register. - pub fn set_mtime(&self, time: ::aonclk::Ticks) { - unsafe { - self.0.mtimeh.write(|w| w.bits(time.into_hi())); - self.0.mtime.write(|w| w.bits(time.into())); - } - } - - /// Read mtimecmp register. - pub fn get_mtimecmp(&self) -> ::aonclk::Ticks { - let hi = self.0.mtimecmph.read().bits() as u64; - let lo = self.0.mtimecmp.read().bits() as u64; - ::aonclk::Ticks(hi << 32 | lo) - } - - /// Write mtimecmp register. - pub fn set_mtimecmp(&self, time: ::aonclk::Ticks) { - unsafe { - self.0.mtimecmph.write(|w| w.bits(time.into_hi())); - self.0.mtimecmp.write(|w| w.bits(time.into())); - } - } - - /// Read mcycle register. - pub fn get_mcycle(&self) -> ::coreclk::Ticks { - loop { - let hi = csr::mcycleh.read().bits(); - let lo = csr::mcycle.read().bits(); - if hi == csr::mcycleh.read().bits() { - return ::coreclk::Ticks(((hi as u64) << 32) | lo as u64); - } - } - } - - /// Write mcycle register. - pub fn set_mcycle(&self, cycle: ::coreclk::Ticks) { - csr::mcycleh.write(|w| w.bits(cycle.into_hi())); - csr::mcycle.write(|w| w.bits(cycle.into())); - } - - /// Read minstret register. - pub fn get_minstret(&self) -> u64 { - loop { - let hi = csr::minstreth.read().bits(); - let lo = csr::minstret.read().bits(); - if hi == csr::minstreth.read().bits() { - return ((hi as u64) << 32) | lo as u64; - } - } - } - - /// Write minstret register. - pub fn set_minstret(&self, instret: u64) { - csr::minstreth.write(|w| w.bits((instret >> 32) as u32)); - csr::minstret.write(|w| w.bits(instret as u32)); - } - - - /// Enable Machine-Timer interrupt. - pub fn enable_mtimer(&self) { - csr::mie.set(|w| w.mtimer()); - } - - /// Disable Machine-Timer interrupt. - pub fn disable_mtimer(&self) { - csr::mie.clear(|w| w.mtimer()); - } - - /// Check if the Machine-Timer is interrupt pending. - pub fn is_mtimer_pending(&self) -> bool { - csr::mip.read().mtimer() - } - - /// Measure the coreclk frequency by counting the number of aonclk ticks. - pub fn measure_coreclk(&self, min_ticks: ::aonclk::Ticks) -> u32 { - interrupt::free(|_| { - let clint = self.0; - - // Don't start measuring until we see an mtime tick - while clint.mtime.read().bits() == clint.mtime.read().bits() {} - - let start_cycle = self.get_mcycle(); - let start_time = self.get_mtime(); - - // Wait for min_ticks to pass - while start_time + min_ticks > self.get_mtime() {} - - let end_cycle = self.get_mcycle(); - let end_time = self.get_mtime(); - - let delta_cycle: u32 = (end_cycle - start_cycle).into(); - let delta_time: u32 = (end_time - start_time).into(); - - (delta_cycle / delta_time) * 32768 - + ((delta_cycle % delta_time) * 32768) / delta_time - }) - } -} - -impl<'a> ::hal::Timer for Clint<'a> { - type Time = ::aonclk::Ticks; - - fn get_timeout(&self) -> ::aonclk::Ticks { - self.get_mtimecmp() - } - - fn pause(&self) { - self.disable_mtimer(); - } - - fn restart(&self) { - self.set_mtime(::aonclk::Ticks(0)); - self.enable_mtimer(); - } - - fn resume(&self) { - unimplemented!(); - } - - fn set_timeout(&self, timeout: T) - where - T: Into<::aonclk::Ticks>, - { - self.disable_mtimer(); - self.set_mtimecmp(timeout.into()); - self.set_mtime(::aonclk::Ticks(0)); - self.enable_mtimer(); - } - - fn wait(&self) -> ::nb::Result<(), !> { - if self.is_mtimer_pending() { - Ok(()) - } else { - Err(::nb::Error::WouldBlock) - } - } -} diff --git a/src/clock.rs b/src/clock.rs deleted file mode 100644 index 50ec9d2..0000000 --- a/src/clock.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Clock configuration -use e310x::{AONCLK, prci, PRCI}; -use clint::Clint; - -/// Aon Clock interface -pub struct AonClock<'a>(pub &'a AONCLK); - -impl<'a> Clone for AonClock<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Copy for AonClock<'a> {} - -impl<'a> AonClock<'a> { - /// Use external real time oscillator. - pub unsafe fn use_external(&self) { - // The G000 doesn't have a LFXOSC and is hardwired - // to use the an external oscillator. - // Disable unused LFROSC to save power. - self.0.lfrosccfg.write(|w| w.enable().bit(false)); - } -} - -/// Core Clock interface -pub struct CoreClock<'a>(pub &'a PRCI); - -impl<'a> Clone for CoreClock<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Copy for CoreClock<'a> { -} - -impl<'a> CoreClock<'a> { - /// Use external oscillator with bypassed pll. - pub unsafe fn use_external(&self, clint: &Clint) { - self.init_pll(clint, |_, w| { - // bypass PLL - w.bypass().bit(true) - // select HFXOSC - .refsel().bit(true) - }, |w| w.divby1().bit(true)); - // Disable HFROSC to save power - self.0.hfrosccfg.write(|w| w.enable().bit(false)); - } - - /// Use external oscillator with pll. Sets PLL - /// r=2, f=64, q=2 values to maximum allowable - /// for a 16MHz reference clock. Output frequency - /// is 16MHz / 2 * 64 / 2 = 256MHz. - /// NOTE: By trimming the internal clock to 12MHz - /// and using r=1, f=64, q=2 the maximum frequency - /// of 384MHz can be reached. - pub unsafe fn use_pll(&self, clint: &Clint) { - self.init_pll(clint, |_, w| { - // bypass PLL - w.bypass().bit(false) - // select HFXOSC - .refsel().bit(true) - // bits = r - 1 - .pllr().bits(1) - // bits = f / 2 - 1 - .pllf().bits(31) - // bits = q=2 -> 1, q=4 -> 2, q=8 -> 3 - .pllq().bits(1) - }, |w| w.divby1().bit(true)); - // Disable HFROSC to save power - self.0.hfrosccfg.write(|w| w.enable().bit(false)); - } - - /// Compute PLL multiplier. - pub fn pll_mult(&self) -> u32 { - let pllcfg = self.0.pllcfg.read(); - let plloutdiv = self.0.plloutdiv.read(); - - let r = pllcfg.pllr().bits() as u32 + 1; - let f = (pllcfg.pllf().bits() as u32 + 1) * 2; - let q = [2, 4, 8][pllcfg.pllq().bits() as usize - 1]; - - let div = match plloutdiv.divby1().bit() { - true => 1, - false => (plloutdiv.div().bits() as u32 + 1) * 2, - }; - - f / r / q / div - } - - /// Wait for the pll to lock. - unsafe fn wait_for_lock(&self, clint: &Clint) { - // Won't lock when bypassed and will loop forever - if !self.0.pllcfg.read().bypass().bit_is_set() { - // Wait for PLL Lock - // Note that the Lock signal can be glitchy. - // Need to wait 100 us - // RTC is running at 32kHz. - // So wait 4 ticks of RTC. - let time = clint.get_mtime() + ::aonclk::Ticks(4); - while clint.get_mtime() < time {} - // Now it is safe to check for PLL Lock - while !self.0.pllcfg.read().lock().bit_is_set() {} - } - } - - unsafe fn init_pll(&self, clint: &Clint, pllcfg: F, plloutdiv: G) - where - for<'w> F: FnOnce(&prci::pllcfg::R, - &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, - for<'w> G: FnOnce(&'w mut prci::plloutdiv::W) -> &'w mut prci::plloutdiv::W, - { - // Make sure we are running of internal clock - // before configuring the PLL. - self.use_internal(); - // Enable HFXOSC - self.0.hfxosccfg.write(|w| w.enable().bit(true)); - // Wait for HFXOSC to stabilize - while !self.0.hfxosccfg.read().ready().bit_is_set() {} - // Configure PLL - self.0.pllcfg.modify(pllcfg); - self.0.plloutdiv.write(plloutdiv); - // Wait for PLL lock - self.wait_for_lock(clint); - // Switch to PLL - self.0.pllcfg.modify(|_, w| { - w.sel().bit(true) - }); - } - - /// Use internal oscillator with bypassed pll. - pub unsafe fn use_internal(&self) { - // Enable HFROSC - self.0.hfrosccfg.write(|w| { - w.enable().bit(true) - // It is OK to change this even if we are running off of it. - // Reset them to default values. - .div().bits(4) - .trim().bits(16) - }); - // Wait for HFROSC to stabilize - while !self.0.hfrosccfg.read().ready().bit_is_set() {} - // Switch to HFROSC - self.0.pllcfg.modify(|_, w| { - w.sel().bit(false) - }); - // Bypass PLL to save power - self.0.pllcfg.modify(|_, w| { - w.bypass().bit(true) - // Select HFROSC as PLL ref to disable HFXOSC later - .refsel().bit(false) - }); - // Disable HFXOSC to save power. - self.0.hfxosccfg.write(|w| w.enable().bit(false)); - } - - /// Measure the frequency of coreclk. - pub fn measure(&self, clint: &Clint) -> u32 { - // warm up I$ - clint.measure_coreclk(::aonclk::Ticks(1)); - // measure for real - clint.measure_coreclk(::aonclk::Ticks(10)) - } -} diff --git a/src/gpio.rs b/src/gpio.rs deleted file mode 100644 index dd9ff2e..0000000 --- a/src/gpio.rs +++ /dev/null @@ -1,222 +0,0 @@ -//! General Purpose I/O - -use core::ops::Deref; -use e310x::gpio0; - -/// Enumeration of possible pin configurations. -pub enum PinConfig { - Input, - InputPullup, - Output, - OutputDrive, - IoFn0, - IoFn1, -} - -/// Enumeration of pin interrupts. -pub enum PinInterrupt { - Rise, - Fall, - High, - Low, -} - -macro_rules! pin { - ($Pin:ident, $pinx:ident) => ( - pub struct $Pin; - - impl $Pin { - pub fn init(gpio: &T, config: PinConfig) - where - T: Deref, - { - match config { - PinConfig::Input => { - gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); - gpio.pullup.modify(|_, w| w.$pinx().bit(false)); - gpio.input_en.modify(|_, w| w.$pinx().bit(true)); - }, - PinConfig::InputPullup => { - gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); - gpio.pullup.modify(|_, w| w.$pinx().bit(true)); - gpio.input_en.modify(|_, w| w.$pinx().bit(true)); - }, - PinConfig::Output => { - gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); - gpio.drive.modify(|_, w| w.$pinx().bit(false)); - gpio.output_en.modify(|_, w| w.$pinx().bit(true)); - }, - PinConfig::OutputDrive => { - gpio.iof_en.modify(|_, w| w.$pinx().bit(false)); - gpio.drive.modify(|_, w| w.$pinx().bit(true)); - gpio.output_en.modify(|_, w| w.$pinx().bit(true)); - }, - PinConfig::IoFn0 => { - gpio.iof_sel.modify(|_, w| w.$pinx().bit(false)); - gpio.iof_en.modify(|_, w| w.$pinx().bit(true)); - }, - PinConfig::IoFn1 => { - gpio.iof_sel.modify(|_, w| w.$pinx().bit(true)); - gpio.iof_en.modify(|_, w| w.$pinx().bit(true)); - }, - } - } - - pub fn read(gpio: &T) -> bool - where - T: Deref, - { - gpio.value.read().$pinx().bit() - } - - pub fn write(gpio: &T, value: bool) - where - T: Deref, - { - match value { - true => $Pin::high(gpio), - false => $Pin::low(gpio), - } - } - - pub fn high(gpio: &T) - where - T: Deref, - { - gpio.port.modify(|_, w| w.$pinx().bit(true)); - } - - pub fn low(gpio: &T) - where - T: Deref, - { - gpio.port.modify(|_, w| w.$pinx().bit(false)); - } - - pub fn toggle(gpio: &T) - where - T: Deref, - { - gpio.port.modify(|r, w| w.$pinx().bit(!r.$pinx().bit())); - } - - pub fn enable_interrupt(gpio: &T, intr: PinInterrupt) - where - T: Deref, - { - match intr { - PinInterrupt::Rise => - gpio.rise_ie.modify(|_, w| w.$pinx().bit(true)), - PinInterrupt::Fall => - gpio.fall_ie.modify(|_, w| w.$pinx().bit(true)), - PinInterrupt::High => - gpio.high_ie.modify(|_, w| w.$pinx().bit(true)), - PinInterrupt::Low => - gpio.low_ie.modify(|_, w| w.$pinx().bit(true)), - }; - } - - pub fn disable_interrupt(gpio: &T, intr: PinInterrupt) - where - T: Deref, - { - match intr { - PinInterrupt::Rise => - gpio.rise_ie.modify(|_, w| w.$pinx().bit(false)), - PinInterrupt::Fall => - gpio.fall_ie.modify(|_, w| w.$pinx().bit(false)), - PinInterrupt::High => - gpio.high_ie.modify(|_, w| w.$pinx().bit(false)), - PinInterrupt::Low => - gpio.low_ie.modify(|_, w| w.$pinx().bit(false)), - }; - } - - pub fn clear_pending(gpio: &T, intr: PinInterrupt) - where - T: Deref, - { - match intr { - PinInterrupt::Rise => - gpio.rise_ip.write(|w| w.$pinx().bit(true)), - PinInterrupt::Fall => - gpio.fall_ip.write(|w| w.$pinx().bit(true)), - PinInterrupt::High => - gpio.high_ip.write(|w| w.$pinx().bit(true)), - PinInterrupt::Low => - gpio.low_ip.write(|w| w.$pinx().bit(true)), - } - } - - pub fn is_interrupt_pending(gpio: &T, intr: PinInterrupt) -> bool - where - T: Deref, - { - match intr { - PinInterrupt::Rise => - gpio.rise_ip.read().$pinx().bit(), - PinInterrupt::Fall => - gpio.fall_ip.read().$pinx().bit(), - PinInterrupt::High => - gpio.high_ip.read().$pinx().bit(), - PinInterrupt::Low => - gpio.low_ip.read().$pinx().bit(), - } - } - - pub fn is_inverted(gpio: &T) -> bool - where - T: Deref, - { - gpio.out_xor.read().$pinx().bit() - } - - pub fn set_invert(gpio: &T, value: bool) - where - T: Deref, - { - gpio.out_xor.modify(|_, w| w.$pinx().bit(value)); - } - - pub fn invert(gpio: &T) - where - T: Deref, - { - gpio.out_xor.modify(|r, w| w.$pinx().bit(!r.$pinx().bit())); - } - } - ) -} - -pin!(Pin0, pin0); -pin!(Pin1, pin1); -pin!(Pin2, pin2); -pin!(Pin3, pin3); -pin!(Pin4, pin4); -pin!(Pin5, pin5); -pin!(Pin6, pin6); -pin!(Pin7, pin7); -pin!(Pin8, pin8); -pin!(Pin9, pin9); -pin!(Pin10, pin10); -pin!(Pin11, pin11); -pin!(Pin12, pin12); -pin!(Pin13, pin13); -pin!(Pin14, pin14); -pin!(Pin15, pin15); -pin!(Pin16, pin16); -pin!(Pin17, pin17); -pin!(Pin18, pin18); -pin!(Pin19, pin19); -pin!(Pin20, pin20); -pin!(Pin21, pin21); -pin!(Pin22, pin22); -pin!(Pin23, pin23); -pin!(Pin24, pin24); -pin!(Pin25, pin25); -pin!(Pin26, pin26); -pin!(Pin27, pin27); -pin!(Pin28, pin28); -pin!(Pin29, pin29); -pin!(Pin30, pin30); -pin!(Pin31, pin31); diff --git a/src/led.rs b/src/led.rs deleted file mode 100644 index a52d1d8..0000000 --- a/src/led.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! User LEDs -//! -//! - Red = Pin 22 -//! - Green = Pin 19 -//! - Blue = Pin 21 - -use e310x::GPIO0; -use gpio::{PinConfig, Pin22, Pin19, Pin21}; - -pub fn init(gpio: &GPIO0) { - Pin22::set_invert(gpio, true); - Pin22::init(gpio, PinConfig::Output); - Pin19::set_invert(gpio, true); - Pin19::init(gpio, PinConfig::Output); - Pin21::set_invert(gpio, true); - Pin21::init(gpio, PinConfig::Output); -} - -#[macro_export] -macro_rules! led { - ($Color:ident, $Pin:ident) => { - pub struct $Color; - - impl $Color { - pub fn on(gpio: &GPIO0) { - $Pin::high(gpio); - } - - pub fn off(gpio: &GPIO0) { - $Pin::low(gpio); - } - - pub fn toggle(gpio: &GPIO0) { - $Pin::toggle(gpio); - } - } - } -} - -led!(Red, Pin22); -led!(Green, Pin19); -led!(Blue, Pin21); diff --git a/src/lib.rs b/src/lib.rs index d1c93d4..1f1b543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,212 +1,124 @@ +//! Board support crate for the Hifive + +#![deny(missing_docs)] +#![deny(warnings)] #![no_std] -#![feature(asm)] -#![feature(get_type_id)] -#![feature(lang_items)] -#![feature(linkage)] -#![feature(never_type)] -#![feature(try_from)] -#![feature(used)] - -extern crate embedded_hal as hal; -#[macro_use] -extern crate nb; - -pub extern crate riscv; -pub extern crate e310x; - -pub mod clint; -pub mod clock; -pub mod gpio; -pub mod led; -pub mod plic; -pub mod pwm; -pub mod rtc; -pub mod serial; -pub mod time; - -pub use hal::prelude; -pub use riscv::{csr, interrupt}; -pub use e310x::Peripherals; -pub use gpio::{PinConfig, PinInterrupt}; -pub use clint::Clint; -pub use led::{Red, Green, Blue}; -pub use plic::{Priority, Interrupt, Plic}; -pub use pwm::{Align, Channel, Pwm}; -pub use rtc::{Rtc, RtcConf}; -pub use serial::{Serial, Port}; -pub use time::UExt; - -/// Default trap handler -/// -/// Prints trap cause and calls mtimer_trap_handler or plic_trap_handler if -/// necessary. -#[used] -#[no_mangle] -pub fn trap_handler(trap: riscv::csr::Trap) { - use riscv::csr::{Trap, Interrupt}; - - let p = e310x::Peripherals::take().unwrap(); - - match trap { - Trap::Interrupt(x) => { - match x { - Interrupt::MachineTimer => { - mtimer_trap_handler(&p); - }, - Interrupt::MachineExternal => { - let plic = Plic(&p.PLIC); - let intr = plic.claim(); - - plic_trap_handler(&p, &intr); - - plic.complete(intr); - } - x => { - interrupt_trap_handler(&p, x); - }, - } - }, - Trap::Exception(x) => { - let mepc = csr::mepc.read().bits(); - exception_trap_handler(&p, x, mepc); - }, + +pub extern crate e310x_hal as hal; + +pub use serial::{TX, RX, tx_rx}; +pub use led::{RED, GREEN, BLUE, rgb}; + +pub mod serial { + //! Single UART hooked up to FTDI + //! + //! - Tx = Pin 17 + //! - Rx = Pin 16 + use hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; + use hal::gpio::{IOF0, NoInvert}; + + /// UART0 TX Pin + pub type TX = Pin17>; + /// UART0 RX Pin + pub type RX = Pin16>; + + /// Return TX, RX pins. + pub fn tx_rx( + tx: Pin17, rx: Pin16, + out_xor: &mut OUT_XOR, iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN + ) -> (TX, RX) + { + let tx: TX = tx.into_iof0(out_xor, iof_sel, iof_en); + let rx: RX = rx.into_iof0(out_xor, iof_sel, iof_en); + (tx, rx) } } -/// Default MachineTimer Trap Handler -#[no_mangle] -#[linkage = "weak"] -pub fn mtimer_trap_handler(_: &e310x::Peripherals) {} - -/// Default MachineExternal Trap Handler -#[no_mangle] -#[linkage = "weak"] -pub fn plic_trap_handler(_: &e310x::Peripherals, _: &Interrupt) {} - -/// Default Interrupt Trap Handler -/// -/// Only called when interrupt is not a MachineTimer or -/// MachineExternal interrupt. -#[no_mangle] -#[linkage = "weak"] -pub fn interrupt_trap_handler(_: &e310x::Peripherals, _: riscv::csr::Interrupt) {} - -/// Default Exception Trap Handler -#[no_mangle] -#[linkage = "weak"] -pub fn exception_trap_handler(_: &e310x::Peripherals, _: riscv::csr::Exception, _: u32) {} - -macro_rules! ticks_impl { - ($n:ident, $t:ty, $f:expr) => { - pub const $n: $t = $f as $t; - - impl Ticks<$t> { - /// Applies the function `f` to the inner value - pub fn map(self, f: F) -> Ticks<$t> - where F: FnOnce($t) -> $t, - { - Ticks(f(self.0)) - } - } - - impl From> for Microseconds<$t> { - fn from(ticks: Ticks<$t>) -> Microseconds<$t> { - let divisor: $t = $n / 1_000_000; - Microseconds(ticks.0 / divisor) - } - } - - impl From> for Milliseconds<$t> { - fn from(ticks: Ticks<$t>) -> Milliseconds<$t> { - Milliseconds(ticks.0 / ($n / 1_000)) - } - } - - impl From> for Seconds<$t> { - fn from(ticks: Ticks<$t>) -> Seconds<$t> { - Seconds(ticks.0 / $n) - } - } - - impl From> for Ticks<$t> { - fn from(ihz: IHertz<$t>) -> Ticks<$t> { - Ticks($n / ihz.0) - } - } +pub mod led { + //! On-board user LEDs + //! + //! - Red = Pin 22 + //! - Green = Pin 19 + //! - Blue = Pin 21 + use hal::prelude::*; + use hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, + OUT_XOR, IOF_EN}; + use hal::gpio::{Output, Regular, Invert}; + + /// Red LED + pub type RED = Pin22>>; + + /// Green LED + pub type GREEN = Pin19>>; + + /// Blue LED + pub type BLUE = Pin21>>; + + /// Returns RED, GREEN and BLUE LEDs. + pub fn rgb( + red: Pin22, green: Pin19, blue: Pin21, + output_en: &mut OUTPUT_EN, drive: &mut DRIVE, + out_xor: &mut OUT_XOR, iof_en: &mut IOF_EN + ) -> (RED, GREEN, BLUE) + { + let red: RED = red.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + let green: GREEN = green.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + let blue: BLUE = blue.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + (red, green, blue) + } - impl From> for Ticks<$t> { - fn from(us: Microseconds<$t>) -> Ticks<$t> { - Ticks(us.0 * ($n / 1_000_000)) - } - } + /// Generic LED + pub trait Led { + /// Turns the LED off + fn off(&mut self); - impl From> for Ticks<$t> { - fn from(ms: Milliseconds<$t>) -> Ticks<$t> { - Ticks(ms.0 * ($n / 1_000)) - } - } + /// Turns the LED on + fn on(&mut self); + } - impl From> for Ticks<$t> { - fn from(s: Seconds<$t>) -> Ticks<$t> { - Ticks(s.0 * $n) - } + impl Led for RED { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); } - impl Into<$t> for Ticks<$t> { - fn into(self) -> $t { - self.0 - } + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); } + } - impl ::core::ops::Add for Ticks<$t> { - type Output = Ticks<$t>; - - fn add(self, other: Ticks<$t>) -> Ticks<$t> { - Ticks(self.0 + other.0) - } + impl Led for GREEN { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); } - impl ::core::ops::Sub for Ticks<$t> { - type Output = Ticks<$t>; - - fn sub(self, other: Ticks<$t>) -> Ticks<$t> { - Ticks(self.0 - other.0) - } + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); } } -} - -macro_rules! frequency { - ($FREQUENCY:expr) => { - use time::*; - /// Unit of time - #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] - pub struct Ticks(pub T); - - ticks_impl!(FREQUENCY_32, u32, $FREQUENCY); - ticks_impl!(FREQUENCY_64, u64, $FREQUENCY); - - impl Into for Ticks { - fn into(self) -> u32 { - self.0 as u32 - } + impl Led for BLUE { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); } - impl Ticks { - pub fn into_hi(self) -> u32 { - (self.0 >> 32) as u32 - } + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); } } } - -/// Always-On Clock -pub mod aonclk { - frequency!(32_768); -} - -/// Core Clock -pub mod coreclk { - frequency!(16_000_000); -} diff --git a/src/plic.rs b/src/plic.rs deleted file mode 100644 index 91f3ba6..0000000 --- a/src/plic.rs +++ /dev/null @@ -1,190 +0,0 @@ -use core::convert::TryFrom; -use riscv::csr; -use riscv::interrupt::Nr; -use e310x::PLIC; -pub use e310x::Interrupt; - -/// Priority of a plic::Interrupt. -#[derive(Clone, Copy)] -pub enum Priority { - P0, P1, P2, P3, P4, P5, P6, P7, -} - -impl Priority { - /// Takes a read interrupt priority or plic threshold - /// register value and returns a plic::Priority enum. - fn from(prio: u32) -> Priority { - match prio { - 0 => Priority::P0, - 1 => Priority::P1, - 2 => Priority::P2, - 3 => Priority::P3, - 4 => Priority::P4, - 5 => Priority::P5, - 6 => Priority::P6, - 7 => Priority::P7, - _ => unreachable!(), - } - } -} - -impl Into for Priority { - /// Returns the numeric priority for writing to a - /// interrupt priority or the plic threshold register. - fn into(self) -> u32 { - match self { - Priority::P0 => 0, - Priority::P1 => 1, - Priority::P2 => 2, - Priority::P3 => 3, - Priority::P4 => 4, - Priority::P5 => 5, - Priority::P6 => 6, - Priority::P7 => 7, - } - } -} - -/// Plic interface -pub struct Plic<'a>(pub &'a PLIC); - -impl<'a> Clone for Plic<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Copy for Plic<'a> { -} - -/// Represents a register offset and mask for -/// accessing an individual bit in a register -/// file. -struct Loc { - offset: usize, - mask: u32, -} - -impl Loc { - /// Computes the location of an interrupt. - //#[inline] - pub fn from(intr: Interrupt) -> Self { - // offset = nr / 32 - // bit = nr % 32 - // 32 = 2 ^ 5 - let nr = intr.nr(); - let bit = nr & 31; - Self { - offset: (nr >> 5) as usize, - mask: 1 << bit - } - } - - /// Checks if bit is set. - //#[inline] - pub fn is_set(&self, bits: u32) -> bool { - bits & self.mask == self.mask - } -} - -impl<'a> Plic<'a> { - /// Initializes PLIC controller by resetting all - /// enable bits to 0 and enables MachineExternal - /// interrupts. - pub fn init(&self) { - for reg in self.0.enable.iter() { - unsafe { - // bug somewhere enabling interrupts - reg.write(|w| w.bits(0xFFFF_FFFF)); - } - } - self.set_threshold(Priority::P0); - self.enable_mext(); - } - - /// Enable MachineExternal interrupts. - #[inline] - pub fn enable_mext(&self) { - csr::mie.set(|w| w.mext()); - } - - /// Disable MachineExternal interrupts. - #[inline] - pub fn disable_mext(&self) { - csr::mie.clear(|w| w.mext()); - } - - /// Returns true when plic::Interrupt is pending. - pub fn is_pending(&self, intr: Interrupt) -> bool { - let loc = Loc::from(intr); - let pending = self.0.pending[loc.offset].read(); - loc.is_set(pending.bits()) - } - - /// Returns true when plic::Interrupt is enabled. - pub fn is_enabled(&self, intr: Interrupt) -> bool { - let loc = Loc::from(intr); - let enable = self.0.enable[loc.offset].read(); - loc.is_set(enable.bits()) - } - - /// Enables plic::Interrupt. - pub fn enable(&self, intr: Interrupt) { - let loc = Loc::from(intr); - unsafe { - self.0.enable[loc.offset] - .modify(|r, w| w.bits(r.bits() | loc.mask)); - } - } - - /// Disables plic::Interrupt. - pub fn disable(&self, intr: Interrupt) { - let loc = Loc::from(intr); - unsafe { - self.0.enable[loc.offset] - .modify(|r, w| w.bits(r.bits() & !loc.mask)); - } - } - - /// Claims the plic::Interrupt with the highest priority. - pub fn claim(&self) -> Interrupt { - Interrupt::try_from(self.0.claim.read().bits() as u8).unwrap() - } - - /// Notifies the PLIC that the claimed plic::Interrupt is - /// complete. - pub fn complete(&self, intr: Interrupt) { - unsafe { - self.0.claim.write(|w| w.bits(intr.nr() as u32)); - } - } - - /// Returns the plic::Priority of a plic::Interrupt. - pub fn get_priority(&self, _intr: Interrupt) -> Priority { - // Priority array is offset by one. - Priority::from(0) - //Priority::from(self.0.priority[intr.nr() as usize - 1].read().bits()) - } - - /// Sets the plic::Priority of a plic::Interrupt. - pub fn set_priority(&self, _intr: Interrupt, _prio: Priority) { - // Priority array is offset by one. - /*unsafe { - self.0.priority[intr.nr() as usize - 1] - .write(|w| w.bits(prio.into())); - }*/ - } - - /// Returns the PLIC threshold priority. - pub fn get_threshold(&self) -> Priority { - Priority::from(self.0.threshold.read().bits()) - } - - /// Sets the PLIC threshold priority. This disables all - /// interrupts with a lower plic::Priority. - pub fn set_threshold(&self, prio: Priority) { - unsafe { - self.0.threshold.write(|w| w.bits(prio.into())); - } - } -} diff --git a/src/pwm.rs b/src/pwm.rs deleted file mode 100644 index a105226..0000000 --- a/src/pwm.rs +++ /dev/null @@ -1,515 +0,0 @@ -//! Pulse Width Modulation -//! -//! You can use the `Pwm` interface with these PWM instances -//! -//! # PWM0 -//! -//! - CH0: Pin 0 IOF1 -//! - CH1: Pin 1 IOF1 -//! - CH2: Pin 2 IOF1 -//! - CH3: Pin 3 IOF1 -//! -//! # PWM1 -//! -//! - CH0: Pin 20 IOF1 -//! - CH1: Pin 19 IOF1 -//! - CH2: Pin 21 IOF1 -//! - CH3: Pin 22 IOF1 -//! -//! # PWM2 -//! -//! - CH0: Pin 10 IOF1 -//! - CH1: Pin 11 IOF1 -//! - CH2: Pin 12 IOF1 -//! - CH3: Pin 13 IOF1 - -use core::any::{Any, TypeId}; -use core::ops::Deref; - -use e310x::{pwm0, PWM0, PWM1, PWM2, gpio0, GPIO0}; -use gpio::{PinConfig, Pin0, Pin1, Pin2, Pin3, Pin20, Pin19, - Pin21, Pin22, Pin10, Pin11, Pin12, Pin13}; - -/// Channel -#[derive(Clone, Copy, Debug)] -pub enum Channel { - /// CH0 - _0, - /// CH1 - _1, - /// CH2 - _2, - /// CH3 - _3, -} - -/// Channel -#[derive(Clone, Copy, Debug)] -pub enum Align { - /// Left - Left, - /// Center - Center, - /// Right - Right, -} - -/// IMPLEMENTATION DETAIL -pub unsafe trait PWM: Deref { - /// IMPLEMENTATION DETAIL - type GPIO: Deref; -} - -unsafe impl PWM for PWM0 { - type GPIO = GPIO0; -} - -unsafe impl PWM for PWM1 { - type GPIO = GPIO0; -} - -unsafe impl PWM for PWM2 { - type GPIO = GPIO0; -} - -pub struct Pwm<'a, T>(pub &'a T) - where - T: 'a; - -impl<'a, T> Clone for Pwm<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T> Copy for Pwm<'a, T> {} - -impl<'a, T> Pwm<'a, T> - where - T: Any + PWM, -{ - pub fn init(&self) { - unsafe { - self.0.cfg.modify(|_, w| { - w.enalways().bit(true) - // set period of 1s - .scale().bits(8) - .zerocmp().bit(true) - }); - self.0.count.write(|w| w.bits(0)); - } - } - - pub fn enable(&self, channel: Channel, align: Align, gpio: &T::GPIO) { - if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => { - Pin0::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin0::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin0::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin0::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_1 => { - Pin1::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin1::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin1::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin1::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_2 => { - Pin2::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin2::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin2::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin2::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_3 => { - Pin3::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin3::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin3::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin3::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => { - Pin20::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin20::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin20::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin20::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_1 => { - Pin19::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin19::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin19::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin19::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_2 => { - Pin21::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin21::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin21::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin21::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_3 => { - Pin22::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin22::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin22::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin22::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => { - Pin10::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin10::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin10::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin10::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_1 => { - Pin11::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin11::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin11::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin11::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_2 => { - Pin12::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin12::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin12::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin12::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - Channel::_3 => { - Pin13::init(gpio, PinConfig::IoFn1); - match align { - Align::Left => { - Pin13::set_invert(gpio, true); - self.set_center(channel, false); - }, - Align::Center => { - Pin13::set_invert(gpio, false); - self.set_center(channel, true); - }, - Align::Right => { - Pin13::set_invert(gpio, false); - self.set_center(channel, false); - } - } - }, - } - } - } - - pub fn disable(&self, channel: Channel, gpio: &T::GPIO) { - if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin0::init(gpio, PinConfig::Input), - Channel::_1 => Pin1::init(gpio, PinConfig::Input), - Channel::_2 => Pin2::init(gpio, PinConfig::Input), - Channel::_3 => Pin3::init(gpio, PinConfig::Input), - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin20::init(gpio, PinConfig::Input), - Channel::_1 => Pin19::init(gpio, PinConfig::Input), - Channel::_2 => Pin21::init(gpio, PinConfig::Input), - Channel::_3 => Pin22::init(gpio, PinConfig::Input), - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin10::init(gpio, PinConfig::Input), - Channel::_1 => Pin11::init(gpio, PinConfig::Input), - Channel::_2 => Pin12::init(gpio, PinConfig::Input), - Channel::_3 => Pin13::init(gpio, PinConfig::Input), - } - } - } - - pub fn invert(&self, channel: Channel, gpio: &T::GPIO) { - if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin0::invert(gpio), - Channel::_1 => Pin1::invert(gpio), - Channel::_2 => Pin2::invert(gpio), - Channel::_3 => Pin3::invert(gpio), - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin20::invert(gpio), - Channel::_1 => Pin19::invert(gpio), - Channel::_2 => Pin21::invert(gpio), - Channel::_3 => Pin22::invert(gpio), - } - } else if self.0.get_type_id() == TypeId::of::() { - match channel { - Channel::_0 => Pin10::invert(gpio), - Channel::_1 => Pin11::invert(gpio), - Channel::_2 => Pin12::invert(gpio), - Channel::_3 => Pin13::invert(gpio), - } - } - } - - pub fn set_period

(&self, period: P) - where P: Into<::coreclk::Ticks> - { - let ticks: u32 = period.into().into(); - let scale = u16::max_value() as u32 / ticks; - assert!(scale < 0x10); - ::riscv::asm::ebreak(); - unsafe { - self.0.cfg.modify(|_, w| w.scale().bits(scale as u8)); - } - } - - pub fn get_period(&self) -> ::coreclk::Ticks { - let scale = self.0.cfg.read().scale().bits(); - ::coreclk::Ticks(scale as u32 * u16::max_value() as u32) - } - - pub fn align_left(&self, channel: Channel, gpio: &T::GPIO) { - match channel { - Channel::_0 => { - self.0.cfg.modify(|_, w| w.cmp0center().bit(false)); - self.invert(channel, gpio); - }, - Channel::_1 => { - self.0.cfg.modify(|_, w| w.cmp1center().bit(false)); - self.invert(channel, gpio); - }, - Channel::_2 => { - self.0.cfg.modify(|_, w| w.cmp2center().bit(false)); - self.invert(channel, gpio); - } - Channel::_3 => { - self.0.cfg.modify(|_, w| w.cmp3center().bit(false)); - self.invert(channel, gpio); - } - } - } - - fn set_center(&self, channel: Channel, value: bool) { - match channel { - Channel::_0 => self.0.cfg.modify(|_, w| w.cmp0center().bit(value)), - Channel::_1 => self.0.cfg.modify(|_, w| w.cmp1center().bit(value)), - Channel::_2 => self.0.cfg.modify(|_, w| w.cmp2center().bit(value)), - Channel::_3 => self.0.cfg.modify(|_, w| w.cmp3center().bit(value)), - } - } - - pub fn get_cmp(&self, channel: Channel) -> u16 { - match channel { - Channel::_0 => self.0.cmp0.read().value().bits(), - Channel::_1 => self.0.cmp1.read().value().bits(), - Channel::_2 => self.0.cmp2.read().value().bits(), - Channel::_3 => self.0.cmp3.read().value().bits(), - } - } - - pub fn set_cmp(&self, channel: Channel, cmp: u16) { - unsafe { - match channel { - Channel::_0 => self.0.cmp0.write(|w| w.value().bits(cmp)), - Channel::_1 => self.0.cmp1.write(|w| w.value().bits(cmp)), - Channel::_2 => self.0.cmp2.write(|w| w.value().bits(cmp)), - Channel::_3 => self.0.cmp3.write(|w| w.value().bits(cmp)), - } - } - } -} - -/* -/// `hal::Pwm` implementation -impl<'a, T> hal::Pwm for Pwm<'a, T> - where - T: Any + PWM, -{ - type Channel = Channel; - type Duty = u16; - type Time = ::coreclk::Ticks; - - fn get_duty(&self, channel: Channel) -> u16 { - self.get_cmp(channel) - } - - fn disable(&self, channel: Channel) { - - } - - fn enable(&self, channel: Channel) { - - } - - fn get_max_duty(&self) -> u16 { - u16::max_value() - } - - fn get_period(&self) -> ::coreclk::Ticks { - self.get_period() - } - - fn set_duty(&self, channel: Channel, duty: u16) { - self.set_cmp(channel, duty); - } - - fn set_period

(&self, period: P) - where - P: Into<::coreclk::Ticks>, - { - self.set_period(period.into()); - } -} - -#[allow(unused_variables)] -/// `hal::Timer` implementation -impl<'a, T> hal::Timer for Pwm<'a, T> - where - T: Any + PWM -{ - type Time = ::coreclk::Ticks; - - fn get_timeout(&self) -> ::coreclk::Ticks { - ::coreclk::Ticks(10) - } - - fn pause(&self) { - - } - - fn restart(&self) { - - } - - fn resume(&self) { - - } - - fn set_timeout(&self, timeout: TO) - where - TO: Into<::coreclk::Ticks>, - { - - } - - fn wait(&self) -> nb::Result<(), !> { - Ok(()) - } -} -*/ diff --git a/src/rtc.rs b/src/rtc.rs deleted file mode 100644 index cc8b41d..0000000 --- a/src/rtc.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! RTC -use e310x::RTC; - -/// Rtc configuration -pub struct RtcConf { - enalways: bool, - scale: u8, - counter: u64, - cmp: u32, -} - -impl RtcConf { - pub fn new() -> Self { - Self { - enalways: true, - scale: 0, - counter: 0, - cmp: 0, - } - } - - pub fn set_enalways(&mut self, en: bool) -> &mut Self { - self.enalways = en; - self - } - - pub fn set_scale(&mut self, scale: u8) -> &mut Self { - assert!(scale < 16); - self.scale = scale; - self - } - - pub fn set_counter(&mut self, counter: u64) -> &mut Self { - assert!(counter < (1 << 49) - 1); - self.counter = counter; - self - } - pub fn set_cmp(&mut self, cmp: u32) -> &mut Self { - self.cmp = cmp; - self - } - - pub fn end(&self, rtc: &RTC) { - let rtc = Rtc(rtc); - unsafe { - rtc.0.rtccfg.modify(|_, w| { - w.enalways().bit(self.enalways) - .scale().bits(self.scale) - }); - - rtc.0.rtchi.write(|w| w.bits((self.counter >> 32) as u32)); - rtc.0.rtclo.write(|w| w.bits(self.counter as u32)); - rtc.0.rtccmp.write(|w| w.bits(self.cmp)); - } - } -} - - -/// Rtc interface -pub struct Rtc<'a>(pub &'a RTC); - -impl<'a> Clone for Rtc<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Copy for Rtc<'a> {} - -impl<'a> ::hal::Timer for Rtc<'a> { - type Time = ::aonclk::Ticks; - - fn get_timeout(&self) -> ::aonclk::Ticks { - ::aonclk::Ticks(self.0.rtccmp.read().bits()) - } - - fn pause(&self) { - self.0.rtccfg.modify(|_, w| w.enalways().bit(false)); - } - - fn restart(&self) { - unsafe { - self.0.rtchi.write(|w| w.bits(0)); - self.0.rtclo.write(|w| w.bits(0)); - } - self.0.rtccfg.modify(|_, w| w.enalways().bit(true)); - } - - fn resume(&self) { - self.0.rtccfg.modify(|_, w| w.enalways().bit(true)); - } - - fn set_timeout(&self, timeout: T) - where - T: Into<::aonclk::Ticks>, - { - self.pause(); - unsafe { - self.0.rtccmp.write(|w| w.bits(timeout.into().into())); - } - self.restart(); - } - - fn wait(&self) -> ::nb::Result<(), !> { - if self.0.rtccfg.read().cmpip().bit() { - Ok(()) - } else { - Err(::nb::Error::WouldBlock) - } - } -} diff --git a/src/serial.rs b/src/serial.rs deleted file mode 100644 index 0008043..0000000 --- a/src/serial.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Serial interface -//! -//! You can use the `Serial` interface with these UART instances -//! -//! # UART0 -//! - TX: Pin 17 IOF0 -//! - RX: Pin 16 IOF0 -//! - Interrupt::UART0 -//! -//! # UART1 -//! - TX: Pin 25 IOF0 -//! - RX: Pin 24 IOF0 -//! - Interrupt::UART1 - - -use core::any::{Any, TypeId}; -use core::ops::Deref; -use e310x::{gpio0, GPIO0, uart0, UART0, UART1}; -use gpio::{PinConfig, Pin17, Pin16, Pin25, Pin24}; - -/// IMPLEMENTATION DETAIL -pub unsafe trait Uart: Deref { - /// IMPLEMENTATION DETAIL - type GPIO: Deref; - type Ticks: Into; -} - -unsafe impl Uart for UART0 { - type GPIO = GPIO0; - type Ticks = ::coreclk::Ticks; -} - -unsafe impl Uart for UART1 { - type GPIO = GPIO0; - type Ticks = ::coreclk::Ticks; -} - -/// Serial interface -pub struct Serial<'a, U>(pub &'a U) -where - U: Any + Uart; - -impl<'a, U> Clone for Serial<'a, U> -where - U: Any + Uart, -{ - fn clone(&self) -> Self { - *self - } -} - -impl<'a, U> Copy for Serial<'a, U> -where - U: Any + Uart, -{ -} - -impl<'a, U> Serial<'a, U> -where - U: Any + Uart, -{ - /// Initializes the serial interface with a baud rate of `baud_rate` bits - /// per second - pub fn init(&self, baud_rate: B, gpio: &U::GPIO) - where B: Into, - { - if self.0.get_type_id() == TypeId::of::() { - Pin16::init(gpio, PinConfig::IoFn0); - Pin17::init(gpio, PinConfig::IoFn0); - } else if self.0.get_type_id() == TypeId::of::() { - Pin24::init(gpio, PinConfig::IoFn0); - Pin25::init(gpio, PinConfig::IoFn0); - } - - unsafe { - let div = baud_rate.into().into(); - self.0.div.write(|w| w.bits(div)); - - self.0.txctrl.write(|w| w.enable().bit(true)); - self.0.rxctrl.write(|w| w.enable().bit(true)); - } - } -} - -impl<'a, U> ::hal::serial::Read for Serial<'a, U> -where - U: Any + Uart, -{ - type Error = !; - - fn read(&self) -> ::nb::Result { - let uart = self.0; - let rxdata = uart.rxdata.read(); - - if rxdata.empty().bit_is_set() { - Err(::nb::Error::WouldBlock) - } else { - Ok(rxdata.data().bits() as u8) - } - } -} - -impl<'a, U> ::hal::serial::Write for Serial<'a, U> -where - U: Any + Uart, -{ - type Error = !; - - fn write(&self, byte: u8) -> ::nb::Result<(), !> { - let uart = self.0; - let txdata = uart.txdata.read(); - - if txdata.full().bit_is_set() { - Err(::nb::Error::WouldBlock) - } else { - unsafe { - uart.txdata.write(|w| w.data().bits(byte)); - } - Ok(()) - } - } -} - -/// Port -pub struct Port<'p, T>(pub &'p T) - where - T: 'p; - -impl<'p, T> ::core::fmt::Write for Port<'p, T> - where - T: ::hal::serial::Write, -{ - fn write_str(&mut self, s: &str) -> ::core::fmt::Result { - for byte in s.as_bytes() { - let res = block!(self.0.write(*byte)); - - if res.is_err() { - return Err(::core::fmt::Error); - } - - if *byte == '\n' as u8 { - let res = block!(self.0.write('\r' as u8)); - - if res.is_err() { - return Err(::core::fmt::Error); - } - } - } - Ok(()) - } -} diff --git a/src/time.rs b/src/time.rs deleted file mode 100644 index ed86a9f..0000000 --- a/src/time.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! Units of time - -macro_rules! map { - ($Self:ident) => { - impl $Self { - /// Applies the function `f` to inner value - pub fn map(self, f: F) -> $Self - where - F: FnOnce(T) -> T - { - $Self(f(self.0)) - } - } - } -} - -/// `Hz^-1` -#[derive(Clone, Copy, Debug)] -pub struct IHertz(pub T); - -impl IHertz { - /// Invert this quantity - pub fn invert(self) -> Hertz { - Hertz(self.0) - } -} - -map!(IHertz); - -/// `Hz` -#[derive(Clone, Copy, Debug)] -pub struct Hertz(pub T); - -impl Hertz { - /// Invert this quantity - pub fn invert(self) -> IHertz { - IHertz(self.0) - } -} - -map!(Hertz); - -/// `us` -#[derive(Clone, Copy, Debug)] -pub struct Microseconds(pub T); - -map!(Microseconds); - -/// `ms` -#[derive(Clone, Copy, Debug)] -pub struct Milliseconds(pub T); - -map!(Milliseconds); - -/// `s` -#[derive(Clone, Copy, Debug)] -pub struct Seconds(pub T); - -map!(Seconds); - -/// `u32` and `u64` extension trait -pub trait UExt { - /// Wrap in `Hz` - fn hz(self) -> Hertz; - - /// Wrap in `Milliseconds` - fn ms(self) -> Milliseconds; - - /// Wrap in `Seconds` - fn s(self) -> Seconds; - - /// Wrap in `Microseconds` - fn us(self) -> Microseconds; -} - -impl UExt for u32 { - fn hz(self) -> Hertz { - Hertz(self) - } - - fn ms(self) -> Milliseconds { - Milliseconds(self) - } - - fn s(self) -> Seconds { - Seconds(self) - } - - fn us(self) -> Microseconds { - Microseconds(self) - } -} - -impl UExt for u64 { - fn hz(self) -> Hertz { - Hertz(self) - } - - fn ms(self) -> Milliseconds { - Milliseconds(self) - } - - fn s(self) -> Seconds { - Seconds(self) - } - - fn us(self) -> Microseconds { - Microseconds(self) - } -} From 3ad3b13b84a4668b203c9f7f4d24a0a0aab41597 Mon Sep 17 00:00:00 2001 From: David Craven Date: Tue, 27 Mar 2018 20:19:33 +0200 Subject: [PATCH 024/315] Add first batch of drivers. --- Cargo.toml | 9 +- build.rs | 46 ++++++ memory.x | 22 +++ src/clint.rs | 189 +++++++++++++++++++++ src/clock.rs | 320 +++++++++++++++++++++++++++++++++++ src/gpio.rs | 439 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 33 +++- src/plic.rs | 260 +++++++++++++++++++++++++++++ src/prelude.rs | 11 ++ src/serial.rs | 164 ++++++++++++++++++ src/stdout.rs | 32 ++++ src/time.rs | 68 ++++++++ 12 files changed, 1585 insertions(+), 8 deletions(-) create mode 100644 build.rs create mode 100644 memory.x create mode 100644 src/clint.rs create mode 100644 src/clock.rs create mode 100644 src/gpio.rs create mode 100644 src/plic.rs create mode 100644 src/prelude.rs create mode 100644 src/serial.rs create mode 100644 src/stdout.rs create mode 100644 src/time.rs diff --git a/Cargo.toml b/Cargo.toml index 87b70ca..ea8c211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,14 @@ keywords = ["riscv", "e310", "hal"] license = "ISC" [dependencies] -embedded-hal = "0.1.2" +embedded-hal = { version = "0.1.2", features = ["unproven"] } +nb = "0.1.1" riscv = { path = "../riscv" } riscv-rt = { path = "../riscv-rt" } e310x = { path = "../e310x", features = ["rt"] } + +[features] +default = ["pll", "hfxosc", "lfaltclk"] +pll = [] +hfxosc = [] +lfaltclk = [] \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..5a4afec --- /dev/null +++ b/build.rs @@ -0,0 +1,46 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +/// Put the linker script somewhere the linker can find it. +fn memory_linker_script() { + let out_dir = env::var("OUT_DIR").expect("No out dir"); + let dest_path = Path::new(&out_dir); + let mut f = File::create(&dest_path.join("memory.x")) + .expect("Could not create file"); + + f.write_all(include_bytes!("memory.x")) + .expect("Could not write file"); + + println!("cargo:rustc-link-search={}", dest_path.display()); + println!("cargo:rerun-if-changed=memory.x"); +} + +fn external_clock_frequency() { + let out_dir = env::var("OUT_DIR").expect("No out dir"); + let dest_path = Path::new(&out_dir).join("constants.rs"); + let mut f = File::create(&dest_path).expect("Could not create file"); + + let hfxosc_freq = option_env!("BOARD_HFXOSC_FREQ").unwrap_or("16000000"); + let lfaltclk_freq = option_env!("BOARD_LFALTCLK_FREQ").unwrap_or("32768"); + + let hfxosc_freq: u32 = str::parse(hfxosc_freq) + .expect("Could not parse BOARD_HFXOSC_FREQ"); + let lfaltclk_freq: u32 = str::parse(lfaltclk_freq) + .expect("Could not parse BOARD_LFALTCLK_FREQ"); + + writeln!(&mut f, "const BOARD_HFXOSC_FREQ: u32 = {};", hfxosc_freq) + .expect("Could not write file"); + writeln!(&mut f, "const BOARD_LFALTCLK_FREQ: u32 = {};", lfaltclk_freq) + .expect("Could not write file"); + + println!("cargo:rerun-if-env-changed=BOARD_HFXOSC_FREQ"); + println!("cargo:rerun-if-env-changed=BOARD_LFALTCLK_FREQ"); +} + +fn main() { + memory_linker_script(); + external_clock_frequency(); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..c991460 --- /dev/null +++ b/memory.x @@ -0,0 +1,22 @@ +MEMORY +{ +/* NOTE K = KiBi = 1024 bytes */ +/* TODO Adjust these memory regions to match your device memory layout */ +FLASH : ORIGIN = 0x20400000, LENGTH = 512M +RAM : ORIGIN = 0x80000000, LENGTH = 16K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* You may want to use this variable to locate the call stack and static +variables in different memory regions. Below is shown the default value */ + +/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ + +/* You can use this symbol to customize the location of the .text section */ +/* If omitted the .text section will be placed right after the .vector_table +section */ +/* This is required only on microcontrollers that store some configuration right +after the vector table */ + +/* _stext = ORIGIN(FLASH); */ diff --git a/src/clint.rs b/src/clint.rs new file mode 100644 index 0000000..9c5a5fa --- /dev/null +++ b/src/clint.rs @@ -0,0 +1,189 @@ +//! Clint + +use riscv::register::{mcycle, mcycleh, minstret, minstreth, mie, mip}; +use e310x::CLINT; + +macro_rules! read64 { + ($hi:expr, $lo:expr) => { + loop { + let hi = $hi; + let lo = $lo; + if hi == $hi { + return ((hi as u64) << 32) | lo as u64; + } + } + } +} + +/// ClintExt trait extends the CLINT peripheral. +pub trait ClintExt { + /// The parts to split the GPIO into. + type Parts; + + /// Splits the GPIO block into independent pins and registers. + fn split(self) -> Self::Parts; +} + +/// Opaque MTIME register +pub struct MTIME { + _0: (), +} + +impl MTIME { + /// Read mtime register. + #[inline] + pub fn mtime_lo(&self) -> u32 { + unsafe { (*CLINT::ptr()).mtime.read().bits() } + } + + /// Read mtimeh register. + #[inline] + pub fn mtime_hi(&self) -> u32 { + unsafe { (*CLINT::ptr()).mtimeh.read().bits() } + } + + /// Read mtime and mtimeh registers. + pub fn mtime(&self) -> u64 { + read64!(self.mtime_hi(), self.mtime_lo()) + } +} + +/// Opaque MTIMECMP register +pub struct MTIMECMP { + _0: (), +} + +impl MTIMECMP { + /// Read mtimecmp register. + #[inline] + pub fn mtimecmp_lo(&self) -> u32 { + unsafe { (*CLINT::ptr()).mtimecmp.read().bits() } + } + + /// Read mtimecmph register. + #[inline] + pub fn mtimecmp_hi(&self) -> u32 { + unsafe { (*CLINT::ptr()).mtimecmph.read().bits() } + } + + /// Read mtimecmp and mtimecmph registers. + pub fn mtimecmp(&self) -> u64 { + read64!(self.mtimecmp_hi(), self.mtimecmp_lo()) + } + + /// Write mtimecmp register + #[inline] + pub fn set_mtimecmp_lo(&mut self, value: u32) { + unsafe { (*CLINT::ptr()).mtimecmp.write(|w| w.bits(value)) }; + } + + /// Write mtimecmph register + #[inline] + pub fn set_mtimecmp_hi(&mut self, value: u32) { + unsafe { (*CLINT::ptr()).mtimecmph.write(|w| w.bits(value)) }; + } + + /// Write mtimecmp and mtimecmph registers. + pub fn set_mtimecmp(&mut self, value: u64) { + self.set_mtimecmp_hi((value >> 32) as u32); + self.set_mtimecmp_lo(value as u32); + } +} + +/// Opaque mcycle register +pub struct MCYCLE { + _0: (), +} + +impl MCYCLE { + /// Read mcycle register. + #[inline] + pub fn mcycle_lo(&self) -> u32 { + mcycle::read() as u32 + } + + /// Read mcycleh register. + #[inline] + pub fn mcycle_hi(&self) -> u32 { + mcycleh::read() as u32 + } + + /// Read mcycle and mcycleh registers. + pub fn mcycle(&self) -> u64 { + read64!(mcycleh::read(), mcycle::read()) + } +} + +/// Opaque minstret register. +pub struct MINSTRET { + _0: (), +} + +impl MINSTRET { + /// Read minstret register. + #[inline] + pub fn minstret_lo(&self) -> u32 { + minstret::read() as u32 + } + + /// Read minstreth register. + #[inline] + pub fn minstret_hi(&self) -> u32 { + minstreth::read() as u32 + } + + /// Read minstret and minstreth registers. + pub fn minstret(&self) -> u64 { + read64!(self.minstret_hi(), self.minstret_lo()) + } +} + +/// Opaque mtimer interrupt handling. +pub struct MTIMER { + _0: (), +} + +impl MTIMER { + /// Enable Machine-Timer interrupt. + pub fn enable(&mut self) { + unsafe { mie::set_mtimer() }; + } + + /// Disable Machine-Timer interrupt. + pub fn disable(&mut self) { + unsafe { mie::clear_mtimer(); } + } + + /// Check if the Machine-Timer is interrupt pending. + pub fn is_pending(&self) -> bool { + mip::read().mtimer() + } +} + +/// Parts of CLINT peripheral for fine grained permission control. +pub struct ClintParts { + /// Opaque mtimecmp register + pub mtimecmp: MTIMECMP, + /// Opaque mtime register + pub mtime: MTIME, + /// Opaque mcycle register + pub mcycle: MCYCLE, + /// Opaque minstret register + pub minstret: MINSTRET, + /// Opaque mtimer register + pub mtimer: MTIMER, +} + +impl ClintExt for CLINT { + type Parts = ClintParts; + + fn split(self) -> ClintParts { + ClintParts { + mtimecmp: MTIMECMP { _0: () }, + mtime: MTIME { _0: () }, + mcycle: MCYCLE { _0: () }, + minstret: MINSTRET { _0: () }, + mtimer: MTIMER { _0: () }, + } + } +} diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..cc6ed7f --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,320 @@ +//! Clock configuration +use e310x::{prci, PRCI, AONCLK}; +use clint::{MCYCLE, MTIME}; +use riscv::interrupt; +use time::Hertz; + +/// const BOARD_HFXOSC_FREQ: u32 +/// const BOARD_LFALTCLK_FREQ: u32 +include!(concat!(env!("OUT_DIR"), "/constants.rs")); + +/// PrciExt trait extends `PRCI` peripheral. +pub trait PrciExt { + /// Constrains the `PRCI` peripheral so it plays nicely with the other + /// abstractions. + fn constrain(self) -> CoreClk; +} + +/// AonExt trait extends `AONCLK` peripheral. +pub trait AonExt { + /// Constrains the `AON` peripheral so it plays nicely with the other + /// abstractions. + fn constrain(self) -> AonClk; +} + +impl PrciExt for PRCI { + fn constrain(self) -> CoreClk { + if cfg!(feature = "hfxosc") { + CoreClk { + hfxosc: true, + pll: false, + freq: Hertz(BOARD_HFXOSC_FREQ), + } + } else { + CoreClk { + hfxosc: false, + pll: false, + // Default after reset + freq: Hertz(13_800_000), + } + } + } +} + +impl AonExt for AONCLK { + fn constrain(self) -> AonClk { + if cfg!(feature = "lfaltclk") { + AonClk { + lfaltclk: true, + freq: Hertz(BOARD_LFALTCLK_FREQ), + } + } else { + AonClk { + lfaltclk: false, + freq: Hertz(32_768), + } + } + } +} + +/// Constrainted PRCI peripheral +pub struct CoreClk { + hfxosc: bool, + pll: bool, + freq: Hertz, +} + +impl CoreClk { + /// Use external clock. Requires feature hfxosc and BOARD_HFXOSC_FREQ + /// should be set at build time if the external oscillator is not 16MHz. + #[cfg(feature = "hfxosc")] + pub fn use_external(mut self) -> Self { + self.hfxosc = true; + self.freq = Hertz(BOARD_HFXOSC_FREQ); + self + } + + /// Use internal clock. Sets frequency to 13.8MHz. + pub fn use_internal(mut self) -> Self { + self.hfxosc = false; + self.freq = Hertz(13_800_000); + self + } + + /// Use pll. Sets frequency to 256MHz. Requires feature pll. + /// NOTE: Assumes an external 16MHz oscillator is available. + #[cfg(feature = "pll")] + pub fn use_pll(mut self) -> Self { + self.pll = true; + self.freq = Hertz(256_000_000); + self + } + + /// Freezes the clock frequencies. + pub(crate) fn freeze(mut self, mtime: &MTIME) -> Hertz { + if self.pll { + unsafe { self.use_hfpll(mtime); } + } else if self.hfxosc { + unsafe { self.use_hfxosc(mtime); } + } else { + unsafe { self.use_hfrosc(); } + } + + self.freq + } + + /// Use internal oscillator with bypassed pll. + unsafe fn use_hfrosc(&mut self) { + let prci = &*PRCI::ptr(); + + // Enable HFROSC + prci.hfrosccfg.write(|w| { + w.enable().bit(true) + // It is OK to change this even if we are running off of it. + // Reset them to default values. (13.8MHz) + .div().bits(4) + .trim().bits(16) + }); + // Wait for HFROSC to stabilize + while !prci.hfrosccfg.read().ready().bit_is_set() {} + // Switch to HFROSC + prci.pllcfg.modify(|_, w| { + w.sel().bit(false) + }); + // Bypass PLL to save power + prci.pllcfg.modify(|_, w| { + w.bypass().bit(true) + // Select HFROSC as PLL ref to disable HFXOSC later + .refsel().bit(false) + }); + // Disable HFXOSC to save power. + prci.hfxosccfg.write(|w| w.enable().bit(false)); + } + + /// Use external oscillator with bypassed pll. + unsafe fn use_hfxosc(&mut self, mtime: &MTIME) { + let prci = &*PRCI::ptr(); + + self.init_pll(mtime, |_, w| { + // bypass PLL + w.bypass().bit(true) + // select HFXOSC + .refsel().bit(true) + }, |w| w.divby1().bit(true)); + // Disable HFROSC to save power + prci.hfrosccfg.write(|w| w.enable().bit(false)); + } + + /// Use external oscillator with pll. Sets PLL + /// r=2, f=64, q=2 values to maximum allowable + /// for a 16MHz reference clock. Output frequency + /// is 16MHz / 2 * 64 / 2 = 256MHz. + /// NOTE: By trimming the internal clock to 12MHz + /// and using r=1, f=64, q=2 the maximum frequency + /// of 384MHz can be reached. + unsafe fn use_hfpll(&mut self, mtime: &MTIME) { + let prci = &*PRCI::ptr(); + + self.init_pll(mtime, |_, w| { + // bypass PLL + w.bypass().bit(false) + // select HFXOSC + .refsel().bit(true) + // bits = r - 1 + .pllr().bits(1) + // bits = f / 2 - 1 + .pllf().bits(31) + // bits = q=2 -> 1, q=4 -> 2, q=8 -> 3 + .pllq().bits(1) + }, |w| w.divby1().bit(true)); + // Disable HFROSC to save power + prci.hfrosccfg.write(|w| w.enable().bit(false)); + } + + /* + /// Compute PLL multiplier. + fn pll_mult(&self) -> u32 { + let prci = unsafe { &*PRCI::ptr() }; + + let pllcfg = prci.pllcfg.read(); + let plloutdiv = prci.plloutdiv.read(); + + let r = pllcfg.pllr().bits() as u32 + 1; + let f = (pllcfg.pllf().bits() as u32 + 1) * 2; + let q = [2, 4, 8][pllcfg.pllq().bits() as usize - 1]; + + let div = match plloutdiv.divby1().bit() { + true => 1, + false => (plloutdiv.div().bits() as u32 + 1) * 2, + }; + + f / r / q / div + }*/ + + /// Wait for the pll to lock. + fn wait_for_lock(&self, mtime: &MTIME) { + let prci = unsafe { &*PRCI::ptr() }; + // NOTE: reading mtime should always be safe. + + // Won't lock when bypassed and will loop forever + if !prci.pllcfg.read().bypass().bit_is_set() { + // Wait for PLL Lock + // Note that the Lock signal can be glitchy. + // Need to wait 100 us + // RTC is running at 32kHz. + // So wait 4 ticks of RTC. + let time = mtime.mtime() + 4; + while mtime.mtime() < time {} + // Now it is safe to check for PLL Lock + while !prci.pllcfg.read().lock().bit_is_set() {} + } + } + + unsafe fn init_pll(&mut self, mtime: &MTIME, pllcfg: F, plloutdiv: G) + where + for<'w> F: FnOnce(&prci::pllcfg::R, + &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, + for<'w> G: FnOnce(&'w mut prci::plloutdiv::W) -> &'w mut prci::plloutdiv::W, + { + let prci = &*PRCI::ptr(); + // Make sure we are running of internal clock + // before configuring the PLL. + self.use_hfrosc(); + // Enable HFXOSC + prci.hfxosccfg.write(|w| w.enable().bit(true)); + // Wait for HFXOSC to stabilize + while !prci.hfxosccfg.read().ready().bit_is_set() {} + // Configure PLL + prci.pllcfg.modify(pllcfg); + prci.plloutdiv.write(plloutdiv); + // Wait for PLL lock + self.wait_for_lock(mtime); + // Switch to PLL + prci.pllcfg.modify(|_, w| { + w.sel().bit(true) + }); + } +} + +/// Constrained AONCLK peripheral +pub struct AonClk { + lfaltclk: bool, + freq: Hertz, +} + +impl AonClk { + /// Freeze aonclk configuration. + pub(crate) fn freeze(self) -> Hertz { + let aonclk = unsafe { &*AONCLK::ptr() }; + + // Use external real time oscillator. + if self.lfaltclk { + // Disable unused LFROSC to save power. + aonclk.lfrosccfg.write(|w| w.enable().bit(false)); + } + + self.freq + } +} + +/// Frozen clock frequencies +/// +/// The existence of this value indicates that the clock configuration can no +/// longer be changed. +#[derive(Clone, Copy)] +pub struct Clocks { + coreclk: Hertz, + aonclk: Hertz, +} + +impl Clocks { + /// Freezes the coreclk and aonclk frequencies. + pub fn freeze(coreclk: CoreClk, aonclk: AonClk, mtime: &MTIME) -> Self { + let coreclk = coreclk.freeze(mtime); + let aonclk = aonclk.freeze(); + Clocks { coreclk, aonclk } + } + + /// Returns the frozen coreclk frequency + pub fn coreclk(&self) -> Hertz { + self.coreclk + } + + /// Returns the frozen aonclk frequency + pub fn aonclk(&self) -> Hertz { + self.aonclk + } + + /// Measure the coreclk frequency by counting the number of aonclk ticks. + fn _measure_coreclk(&self, min_ticks: u64, mtime: &MTIME, mcycle: &MCYCLE) -> Hertz { + interrupt::free(|_| { + // Don't start measuring until we see an mtime tick + while mtime.mtime() == mtime.mtime() {} + + let start_cycle = mcycle.mcycle(); + let start_time = mtime.mtime(); + + // Wait for min_ticks to pass + while start_time + min_ticks > mtime.mtime() {} + + let end_cycle = mcycle.mcycle(); + let end_time = mtime.mtime(); + + let delta_cycle: u64 = end_cycle - start_cycle; + let delta_time: u64 = end_time - start_time; + + let res = (delta_cycle / delta_time) * 32768 + + ((delta_cycle % delta_time) * 32768) / delta_time; + // u32 can represent 4GHz way above the expected measurement value + Hertz(res as u32) + }) + } + + /// Measure the coreclk frequency by counting the number of aonclk ticks. + pub fn measure_coreclk(&self, mtime: &MTIME, mcycle: &MCYCLE) -> Hertz { + // warm up I$ + self._measure_coreclk(1, mtime, mcycle); + // measure for real + self._measure_coreclk(10, mtime, mcycle) + } +} diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..dab0b09 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,439 @@ +//! General Purpose I/O + +use core::marker::PhantomData; + +/// GpioExt trait extends the GPIO0 peripheral. +pub trait GpioExt { + /// The parts to split the GPIO into. + type Parts; + + /// Splits the GPIO block into independent pins and registers. + fn split(self) -> Self::Parts; +} + + +/// Input mode (type state) +pub struct Input { + _mode: PhantomData, +} + +/// Floating input (type state) +pub struct Floating; +/// Pulled up input (type state) +pub struct PullUp; + +/// Output mode (type state) +pub struct Output { + _mode: PhantomData, +} + +/// Regular output mode (type state) +pub struct Regular { + _mode: PhantomData, +} + +/// High current mode (type state) +pub struct Drive { + _mode: PhantomData, +} + +/// Alternate function 0 (type state) +pub struct IOF0 { + _mode: PhantomData, +} + +/// Alternate function 1 (type state) +pub struct IOF1 { + _mode: PhantomData, +} + +/// Non-inverted output mode (type state) +pub struct NoInvert; + +/// Invert output mode (type state) +pub struct Invert; + + +macro_rules! gpio { + ($GPIOX:ident, $gpiox:ident, $gpioy:ident, [ + $($PXi:ident: ($pxi:ident, $MODE:ty),)+ + ]) => { + /// GPIO + pub mod $gpiox { + use core::marker::PhantomData; + + use hal::digital::{InputPin, OutputPin}; + use e310x::{$gpioy, $GPIOX}; + use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, + NoInvert, Output, PullUp, Regular}; + + /// GPIO parts for fine grained permission control. + pub struct Parts { + /// Opaque INPUT_EN register + pub input_en: INPUT_EN, + /// Opaque OUTPUT_EN register + pub output_en: OUTPUT_EN, + /// Opaque PULLUP register + pub pullup: PULLUP, + /// Opaque DRIVE register + pub drive: DRIVE, + /// Opaque OUT_XOR register + pub out_xor: OUT_XOR, + /// Opaque IOF_EN register + pub iof_en: IOF_EN, + /// Opaque IOF_SEL register + pub iof_sel: IOF_SEL, + $( + /// Pin + pub $pxi: $PXi<$MODE>, + )+ + } + + impl GpioExt for $GPIOX { + type Parts = Parts; + + fn split(self) -> Parts { + Parts { + input_en: INPUT_EN { _0: () }, + output_en: OUTPUT_EN { _0: () }, + pullup: PULLUP { _0: () }, + drive: DRIVE { _0: () }, + out_xor: OUT_XOR { _0: () }, + iof_en: IOF_EN { _0: () }, + iof_sel: IOF_SEL { _0: () }, + $( + $pxi: $PXi { _mode: PhantomData }, + )+ + } + } + } + + /// Opaque INPUT_EN register + #[allow(non_camel_case_types)] + pub struct INPUT_EN { + _0: (), + } + + impl INPUT_EN { + pub(crate) fn input_en(&mut self) -> &$gpioy::INPUT_EN { + unsafe { &(*$GPIOX::ptr()).input_en } + } + } + + /// Opaque OUTPUT_EN register + #[allow(non_camel_case_types)] + pub struct OUTPUT_EN { + _0: (), + } + + impl OUTPUT_EN { + pub(crate) fn output_en(&mut self) -> &$gpioy::OUTPUT_EN { + unsafe { &(*$GPIOX::ptr()).output_en } + } + } + + /// Opaque PULLUP register + pub struct PULLUP { + _0: (), + } + + impl PULLUP { + pub(crate) fn pullup(&mut self) -> &$gpioy::PULLUP { + unsafe { &(*$GPIOX::ptr()).pullup } + } + } + + /// Opaque DRIVE register + pub struct DRIVE { + _0: (), + } + + impl DRIVE { + pub(crate) fn drive(&mut self) -> &$gpioy::DRIVE { + unsafe { &(*$GPIOX::ptr()).drive } + } + } + + + /// Opaque OUT_XOR register + #[allow(non_camel_case_types)] + pub struct OUT_XOR { + _0: (), + } + + impl OUT_XOR { + pub(crate) fn out_xor(&mut self) -> &$gpioy::OUT_XOR { + unsafe { &(*$GPIOX::ptr()).out_xor } + } + } + + /// Opaque IOF_EN register + #[allow(non_camel_case_types)] + pub struct IOF_EN { + _0: (), + } + + impl IOF_EN { + pub(crate) fn iof_en(&mut self) -> &$gpioy::IOF_EN { + unsafe { &(*$GPIOX::ptr()).iof_en } + } + } + + /// Opaque IOF_SEL register + #[allow(non_camel_case_types)] + pub struct IOF_SEL { + _0: (), + } + + impl IOF_SEL { + pub(crate) fn iof_sel(&mut self) -> &$gpioy::IOF_SEL { + unsafe { &(*$GPIOX::ptr()).iof_sel } + } + } + + $( + /// Pin + pub struct $PXi { + _mode: PhantomData, + } + + impl $PXi { + /// Configures the pin to serve as alternate function 0 (AF0) + pub fn into_iof0( + self, + out_xor: &mut OUT_XOR, + iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN + ) -> $PXi> { + out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); + iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(false)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); + + $PXi { _mode: PhantomData } + } + + + /// Configures the pin to serve as alternate function 1 (AF1) + pub fn into_iof1( + self, + out_xor: &mut OUT_XOR, + iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN + ) -> $PXi> { + out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); + iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to serve as inverted alternate function 0 (AF0) + pub fn into_inverted_iof0( + self, + out_xor: &mut OUT_XOR, + iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN + ) -> $PXi> { + out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); + iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(false)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); + + $PXi { _mode: PhantomData } + } + + + /// Configures the pin to serve as inverted alternate function 1 (AF1) + pub fn into_inverted_iof1( + self, + out_xor: &mut OUT_XOR, + iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN + ) -> $PXi> { + out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); + iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to serve as a floating input pin + pub fn into_floating_input( + self, + pullup: &mut PULLUP, + input_en: &mut INPUT_EN, + iof_en: &mut IOF_EN + ) -> $PXi> { + pullup.pullup().modify(|_, w| w.$pxi().bit(false)); + input_en.input_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to operate as a pulled down input pin + pub fn into_pull_up_input( + self, + pullup: &mut PULLUP, + input_en: &mut INPUT_EN, + iof_en: &mut IOF_EN + ) -> $PXi> { + pullup.pullup().modify(|_, w| w.$pxi().bit(true)); + input_en.input_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to operate as an output pin + pub fn into_output( + self, + output_en: &mut OUTPUT_EN, + drive: &mut DRIVE, + out_xor: &mut OUT_XOR, + iof_en: &mut IOF_EN + ) -> $PXi>> { + drive.drive().modify(|_, w| w.$pxi().bit(false)); + out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); + output_en.output_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + + /// Configures the pin to operate as an inverted output pin + pub fn into_inverted_output( + self, + output_en: &mut OUTPUT_EN, + drive: &mut DRIVE, + out_xor: &mut OUT_XOR, + iof_en: &mut IOF_EN + ) -> $PXi>> { + drive.drive().modify(|_, w| w.$pxi().bit(false)); + out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); + output_en.output_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + + /// Configure the pin to operate as an output pin with high + /// current drive + pub fn into_output_drive( + self, + output_en: &mut OUTPUT_EN, + drive: &mut DRIVE, + out_xor: &mut OUT_XOR, + iof_en: &mut IOF_EN + ) -> $PXi>> { + drive.drive().modify(|_, w| w.$pxi().bit(true)); + out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); + output_en.output_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + + /// Configure the pin to operate as an inverted output pin with + /// high current drive + pub fn into_inverted_output_drive( + self, + output_en: &mut OUTPUT_EN, + drive: &mut DRIVE, + out_xor: &mut OUT_XOR, + iof_en: &mut IOF_EN + ) -> $PXi>> { + drive.drive().modify(|_, w| w.$pxi().bit(true)); + out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); + output_en.output_en().modify(|_, w| w.$pxi().bit(true)); + iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); + + $PXi { _mode: PhantomData } + } + } + + impl InputPin for $PXi> { + fn is_high(&self) -> bool { + !self.is_low() + } + + fn is_low(&self) -> bool { + let gpio = unsafe { &*$GPIOX::ptr() }; + // NOTE unsafe atomic read with no side effects + gpio.value.read().$pxi().bit() + } + } + + impl OutputPin for $PXi> { + fn is_high(&self) -> bool { + !self.is_low() + } + + fn is_low(&self) -> bool { + // NOTE unsafe atomic read with no side effects + let gpio = unsafe { &*$GPIOX::ptr() }; + gpio.value.read().$pxi().bit() + } + + fn set_high(&mut self) { + // FIXME has to read register first + // use atomics + let gpio = unsafe { &*$GPIOX::ptr() }; + gpio.port.modify(|_, w| w.$pxi().bit(true)); + } + + fn set_low(&mut self) { + // FIXME: has to read register first + // use atomics + let gpio = unsafe { &*$GPIOX::ptr() }; + gpio.port.modify(|_, w| w.$pxi().bit(false)); + } + } + + impl $PXi> { + /// Toggles the pin state. + pub fn toggle(&mut self) { + // FIXME: has to read register first + // use atomics + let gpio = unsafe { &*$GPIOX::ptr() }; + gpio.port.modify(|r, w| w.$pxi().bit(!r.$pxi().bit())); + } + } + )+ + } + } +} + +gpio!(GPIO0, gpio0, gpio0, [ + Pin0: (pin0, Input), + Pin1: (pin1, Input), + Pin2: (pin2, Input), + Pin3: (pin3, Input), + Pin4: (pin4, Input), + Pin5: (pin5, Input), + Pin6: (pin6, Input), + Pin7: (pin7, Input), + Pin8: (pin8, Input), + Pin9: (pin9, Input), + Pin10: (pin10, Input), + Pin11: (pin11, Input), + Pin12: (pin12, Input), + Pin13: (pin13, Input), + Pin14: (pin14, Input), + Pin15: (pin15, Input), + Pin16: (pin16, Input), + Pin17: (pin17, Input), + Pin18: (pin18, Input), + Pin19: (pin19, Input), + Pin20: (pin20, Input), + Pin21: (pin21, Input), + Pin22: (pin22, Input), + Pin23: (pin23, Input), + Pin24: (pin24, Input), + Pin25: (pin25, Input), + Pin26: (pin26, Input), + Pin27: (pin27, Input), + Pin28: (pin28, Input), + Pin29: (pin29, Input), + Pin30: (pin30, Input), + Pin31: (pin31, Input), +]); diff --git a/src/lib.rs b/src/lib.rs index 31e1bb2..3b08577 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,26 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +//! HAL for the E310x family of microcontrollers +//! +//! This is an implementation of the [`embedded-hal`] traits for the E310x +//! family of microcontrollers. + +#![deny(missing_docs)] +#![deny(warnings)] +#![feature(never_type)] +#![no_std] +#![feature(try_from)] + +extern crate embedded_hal as hal; +#[macro_use] +extern crate nb; + +extern crate riscv; +pub extern crate e310x; + +pub mod clint; +pub mod clock; +pub mod gpio; +pub mod plic; +pub mod prelude; +pub mod serial; +pub mod stdout; +pub mod time; diff --git a/src/plic.rs b/src/plic.rs new file mode 100644 index 0000000..68e83cf --- /dev/null +++ b/src/plic.rs @@ -0,0 +1,260 @@ +//! Plic +use core::convert::TryFrom; +use core::marker::PhantomData; +use riscv::register::{mie, mip}; +use riscv::interrupt::Nr; +use e310x::PLIC; +use e310x::Interrupt; + +/// Priority of a plic::Interrupt. +#[derive(Clone, Copy)] +pub enum Priority { + /// Priority 0: Never interrupt + P0, + /// Priority 1: Lowest active priority + P1, + /// Priority 2 + P2, + /// Priority 3 + P3, + /// Priority 4 + P4, + /// Priority 5 + P5, + /// Priority 6 + P6, + /// Priority 7: Highest priority + P7, +} + +impl Priority { + /// Takes a read interrupt priority or plic threshold + /// register value and returns a plic::Priority enum. + fn from(prio: u32) -> Option { + match prio { + 0 => Some(Priority::P0), + 1 => Some(Priority::P1), + 2 => Some(Priority::P2), + 3 => Some(Priority::P3), + 4 => Some(Priority::P4), + 5 => Some(Priority::P5), + 6 => Some(Priority::P6), + 7 => Some(Priority::P7), + _ => None, + } + } +} + +impl Into for Priority { + /// Returns the numeric priority for writing to a + /// interrupt priority or the plic threshold register. + fn into(self) -> u32 { + match self { + Priority::P0 => 0, + Priority::P1 => 1, + Priority::P2 => 2, + Priority::P3 => 3, + Priority::P4 => 4, + Priority::P5 => 5, + Priority::P6 => 6, + Priority::P7 => 7, + } + } +} + +/// Watchdog interrupt (type state) +pub struct IrqWatchdog; +/// Realtime clock interrupt (type state) +pub struct IrqRtc; +/// Uart0 interrupt (type state) +pub struct IrqUart0; + +/// PlicExt trait extends `PLIC` peripheral. +pub trait PlicExt { + /// Splits the `PLIC` peripheral into parts. + fn split(self) -> PlicParts; +} + +/// Parts of `PLIC` peripheral for fine grained permissions. +pub struct PlicParts { + /// Opaque mext register + pub mext: MEXT, + /// Opaque threshold register + pub threshold: THRESHOLD, + /// Opaque claim register + pub claim: CLAIM, + /// Opaque watchdog register + pub wdog: INTERRUPT, + /// Opaque rtc register + pub rtc: INTERRUPT, + /// Opaque uart0 register + pub uart0: INTERRUPT, +} + +impl PlicExt for PLIC { + fn split(self) -> PlicParts { + PlicParts { + mext: MEXT { _0: () }, + threshold: THRESHOLD { _0: () }, + claim: CLAIM { _0: () }, + wdog: INTERRUPT { + offset: 0, + mask: 1 << (Interrupt::WATCHDOG as u8), + priority_offset: Interrupt::WATCHDOG as usize, + _marker: PhantomData, + }, + rtc: INTERRUPT { + offset: 0, + mask: 1 << (Interrupt::RTC as u8), + priority_offset: Interrupt::RTC as usize, + _marker: PhantomData, + }, + uart0: INTERRUPT { + offset: 0, + mask: 1 << (Interrupt::UART0 as u8), + priority_offset: Interrupt::UART0 as usize, + _marker: PhantomData, + } + } + } +} + +/// Opaque MEXT register. +pub struct MEXT { + _0: (), +} + +impl MEXT { + /// Enable MachineExternal interrupt. + #[inline] + pub fn enable(&mut self) { + unsafe { mie::set_mext() }; + } + + /// Disable MachineExternal interrupt. + #[inline] + pub fn disable(&mut self) { + unsafe { mie::clear_mext() }; + } + + /// Returns true when MachineExternal interrupt is pending. + #[inline] + pub fn is_pending(&self) -> bool { + mip::read().mext() + } +} + +/// Opaque THRESHOLD register. +pub struct THRESHOLD { + _0: (), +} + +impl THRESHOLD { + /// Returns the current active priority threshold. + pub fn get(&self) -> Priority { + // NOTE: Atomic read with no side effects. + let threshold = unsafe { (*PLIC::ptr()).threshold.read() }; + Priority::from(threshold.bits()).unwrap() + } + + /// Sets the current active priority threshold. This + /// deactivates all interrupts with a lower priority. + pub fn set(&mut self, priority: Priority) { + // NOTE: Atomic write with no side effects. + unsafe { + (*PLIC::ptr()).threshold.write(|w| w.bits(priority.into())); + } + } +} + +/// Opaque CLAIM register. +pub struct CLAIM { + _0: (), +} + +impl CLAIM { + /// Claims the interrupt with the highest priority. + pub fn claim(&mut self) -> Interrupt { + // NOTE: Atomic read with side effects. + unsafe { + Interrupt::try_from((*PLIC::ptr()).claim.read().bits() as u8).unwrap() + } + } + + /// Notifies the PLIC that a claimed interrupt is complete. + pub fn complete(&mut self, intr: Interrupt) { + // NOTE: Atomic write with side effects. + unsafe { + (*PLIC::ptr()).claim.write(|w| w.bits(intr.nr() as u32)); + } + } +} + +/// Fine grained interrupt handling. +pub struct INTERRUPT { + /// Offset in to enable and pending plic registers + offset: usize, + /// Bitmask for enable and pending plic registers + mask: u32, + /// Offset in to priority plic registers + priority_offset: usize, + _marker: PhantomData, +} + +impl INTERRUPT { + /// Enable WDOG interrupt. + #[inline] + pub fn enable(&mut self) { + // NOTE: should use atomic operations + unsafe { + (*PLIC::ptr()).enable[self.offset] + .modify(|r, w| w.bits(r.bits() | self.mask)); + } + } + + /// Disable WDOG interrupt. + #[inline] + pub fn disable(&mut self) { + // NOTE: should use atomic operations + unsafe { + (*PLIC::ptr()).enable[self.offset] + .modify(|r, w| w.bits(r.bits() & !self.mask)); + } + } + + /// Returns true when WDOG interrupt is pending. + pub fn is_pending(&self) -> bool { + // NOTE: Atomic write without side effects. + let pending = unsafe { + (*PLIC::ptr()).pending[self.offset].read() + }; + pending.bits() & self.mask == self.mask + } + + /// Returns true when WDOG interrupt is enabled. + pub fn is_enabled(&self) -> bool { + // NOTE: Atomic write without side effects. + let enabled = unsafe { + (*PLIC::ptr()).enable[self.offset].read() + }; + enabled.bits() & self.mask == self.mask + } + + /// Returns the priority of the WDOG interrupt. + pub fn priority(&self) -> Priority { + // NOTE: Atomic read without side effects. + let priority = unsafe { + (*PLIC::ptr()).priority[self.priority_offset].read() + }; + Priority::from(priority.bits()).unwrap() + } + + /// Sets the priority of the WDOG interrupt. + pub fn set_priority(&mut self, priority: Priority) { + // NOTE: Atomic write without side effects. + unsafe { + (*PLIC::ptr()).priority[self.priority_offset] + .write(|w| w.bits(priority as u32)); + } + } +} diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..48b87bd --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,11 @@ +//! Prelude + +pub use hal::prelude::*; +pub use clint::ClintExt as _e310x_hal_clint_ClintExt; +pub use clock::Clocks; +pub use clock::PrciExt as _e310x_hal_clock_PrciExt; +pub use clock::AonExt as _e310x_hal_clock_AonExt; +pub use gpio::GpioExt as _e310x_hal_gpio_GpioExt; +pub use plic::PlicExt as _e310x_hal_plic_PlicExt; +pub use serial::{Serial, Tx, Rx}; +pub use time::U32Ext as _e310x_hal_time_U32Ext; diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 0000000..6c8265c --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,164 @@ +//! Serial interface +//! +//! You can use the `Serial` interface with these UART instances +//! +//! # UART0 +//! - TX: Pin 17 IOF0 +//! - RX: Pin 16 IOF0 +//! - Interrupt::UART0 +//! +//! # UART1 +//! - TX: Pin 25 IOF0 +//! - RX: Pin 24 IOF0 +//! - Interrupt::UART1 +//! Pins not connected to package in E310-G000 + +use core::marker::PhantomData; + +use hal::serial; +use nb; + +use e310x::UART0; +use clock::Clocks; +use gpio::{IOF0, gpio0}; +use plic::{INTERRUPT, IrqUart0}; +use time::Bps; + +// FIXME these should be "closed" traits +/// TX pin - DO NOT IMPLEMENT THIS TRAIT +pub unsafe trait TxPin {} + +/// RX pin - DO NOT IMPLEMENT THIS TRAIT +pub unsafe trait RxPin {} + +unsafe impl TxPin for gpio0::Pin17> {} +unsafe impl RxPin for gpio0::Pin16> {} + +/// Serial abstraction +pub struct Serial { + uart: USART, + pins: PINS, + intr: INTERRUPT, +} + +/// Serial receiver +pub struct Rx { + _usart: PhantomData, +} + +/// Serial transmitter +pub struct Tx { + _usart: PhantomData, +} + +macro_rules! hal { + ($( + $UARTX:ident: $uartX:ident, $IRQ:ty + )+) => { + $( + impl Serial<$UARTX, (TX, RX), $IRQ> { + /// Configures a UART peripheral to provide serial communication + pub fn $uartX( + uart: $UARTX, + pins: (TX, RX), + baud_rate: Bps, + clocks: Clocks, + intr: INTERRUPT<$IRQ> + ) -> Self + where + TX: TxPin<$UARTX>, + RX: RxPin<$UARTX>, + { + let div = clocks.coreclk().0 / baud_rate.0 + 1; + unsafe { uart.div.write(|w| w.bits(div)); } + + uart.txctrl.write(|w| w.enable().bit(true)); + uart.rxctrl.write(|w| w.enable().bit(true)); + + Serial { uart, pins, intr } + } + + /// Starts listening for an interrupt event + pub fn listen(&mut self) { + self.uart.ie.write(|w| w.txwm().bit(true) + .rxwm().bit(true)); + self.intr.enable(); + } + + /// Starts listening for an interrupt event + pub fn unlisten(&mut self) { + self.intr.disable(); + self.uart.ie.write(|w| w.txwm().bit(false) + .rxwm().bit(false)); + } + + /// Splits the `Serial` abstraction into a transmitter and a + /// receiver half + pub fn split(self) -> (Tx<$UARTX>, Rx<$UARTX>) { + ( + Tx { + _usart: PhantomData, + }, + Rx { + _usart: PhantomData, + }, + ) + } + + /// Releases the USART peripheral and associated pins + pub fn free(self) -> ($UARTX, (TX, RX)) { + (self.uart, self.pins) + } + } + + impl serial::Read for Rx<$UARTX> { + type Error = !; + + fn read(&mut self) -> nb::Result { + // NOTE(unsafe) atomic read with no side effects + let rxdata = unsafe { (*$UARTX::ptr()).rxdata.read() }; + + if rxdata.empty().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits() as u8) + } + } + } + + impl serial::Write for Tx<$UARTX> { + type Error = !; + + fn flush(&mut self) -> nb::Result<(), !> { + // NOTE(unsafe) atomic read with no side effects + let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; + + if txdata.full().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } + } + + fn write(&mut self, byte: u8) -> nb::Result<(), !> { + // NOTE(unsafe) atomic read with no side effects + let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; + + if txdata.full().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + unsafe { + (*$UARTX::ptr()).txdata + .write(|w| w.data().bits(byte)); + } + Ok(()) + } + } + } + )+ + } +} + +hal! { + UART0: uart0, IrqUart0 +} diff --git a/src/stdout.rs b/src/stdout.rs new file mode 100644 index 0000000..228637b --- /dev/null +++ b/src/stdout.rs @@ -0,0 +1,32 @@ +//! Stdout +pub use core::fmt::Write; + +/// Stdout implements the core::fmt::Write trait for hal::serial::Write +/// implementations. +pub struct Stdout<'p, T>(pub &'p mut T) + where + T: 'p; + +impl<'p, T> Write for Stdout<'p, T> + where + T: ::hal::serial::Write, +{ + fn write_str(&mut self, s: &str) -> ::core::fmt::Result { + for byte in s.as_bytes() { + let res = block!(self.0.write(*byte)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + + if *byte == '\n' as u8 { + let res = block!(self.0.write('\r' as u8)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + } + } + Ok(()) + } +} diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..c21a86f --- /dev/null +++ b/src/time.rs @@ -0,0 +1,68 @@ +//! Time units + +/// Bits per second +#[derive(Clone, Copy)] +pub struct Bps(pub u32); + +/// Hertz +#[derive(Clone, Copy)] +pub struct Hertz(pub u32); + +/// KiloHertz +#[derive(Clone, Copy)] +pub struct KiloHertz(pub u32); + +/// MegaHertz +#[derive(Clone, Copy)] +pub struct MegaHertz(pub u32); + +/// Extension trait that adds convenience methods to the `u32` type +pub trait U32Ext { + /// Wrap in `Bps` + fn bps(self) -> Bps; + + /// Wrap in `Hertz` + fn hz(self) -> Hertz; + + /// Wrap in `KiloHertz` + fn khz(self) -> KiloHertz; + + /// Wrap in `MegaHertz` + fn mhz(self) -> MegaHertz; +} + +impl U32Ext for u32 { + fn bps(self) -> Bps { + Bps(self) + } + + fn hz(self) -> Hertz { + Hertz(self) + } + + fn khz(self) -> KiloHertz { + KiloHertz(self) + } + + fn mhz(self) -> MegaHertz { + MegaHertz(self) + } +} + +impl Into for KiloHertz { + fn into(self) -> Hertz { + Hertz(self.0 * 1_000) + } +} + +impl Into for MegaHertz { + fn into(self) -> Hertz { + Hertz(self.0 * 1_000_000) + } +} + +impl Into for MegaHertz { + fn into(self) -> KiloHertz { + KiloHertz(self.0 * 1_000) + } +} From d8888dbf4101aac53fb732b7e43d186224ddce08 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 28 Mar 2018 17:54:12 +0200 Subject: [PATCH 025/315] Add rtc driver. --- src/lib.rs | 1 + src/prelude.rs | 1 + src/rtc.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/rtc.rs diff --git a/src/lib.rs b/src/lib.rs index 3b08577..abfc34b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod clock; pub mod gpio; pub mod plic; pub mod prelude; +pub mod rtc; pub mod serial; pub mod stdout; pub mod time; diff --git a/src/prelude.rs b/src/prelude.rs index 48b87bd..23c1264 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,5 +7,6 @@ pub use clock::PrciExt as _e310x_hal_clock_PrciExt; pub use clock::AonExt as _e310x_hal_clock_AonExt; pub use gpio::GpioExt as _e310x_hal_gpio_GpioExt; pub use plic::PlicExt as _e310x_hal_plic_PlicExt; +pub use rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use serial::{Serial, Tx, Rx}; pub use time::U32Ext as _e310x_hal_time_U32Ext; diff --git a/src/rtc.rs b/src/rtc.rs new file mode 100644 index 0000000..0475135 --- /dev/null +++ b/src/rtc.rs @@ -0,0 +1,90 @@ +//! RTC +#![allow(missing_docs)] + +use e310x::RTC; + +pub trait RtcExt { + fn constrain(self) -> Rtc; +} + +impl RtcExt for RTC { + fn constrain(self) -> Rtc { + Rtc { _0: () } + } +} + +pub struct Rtc { + _0: (), +} + +impl Rtc { + #[inline] + pub fn is_pending(&self) -> bool { + unsafe { (*RTC::ptr()).rtccfg.read().cmpip().bit() } + } + + #[inline] + pub fn set_scale(&mut self, scale: u8) { + unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.scale().bits(scale)) }; + } + + #[inline] + pub fn enable(&mut self) { + unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.enalways().bit(true)) } + } + + #[inline] + pub fn disable(&mut self) { + unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.enalways().bit(false)) } + } + + #[inline] + pub fn is_enabled(&self) -> bool { + unsafe { (*RTC::ptr()).rtccfg.read().enalways().bit() } + } + + #[inline] + pub fn rtc_lo(&self) -> u32 { + unsafe { (*RTC::ptr()).rtchi.read().bits() } + } + + #[inline] + pub fn rtc_hi(&self) -> u32 { + unsafe { (*RTC::ptr()).rtclo.read().bits() } + } + + pub fn rtc(&self) -> u64 { + loop { + let hi = self.rtc_hi(); + let lo = self.rtc_lo(); + if hi == self.rtc_hi() { + return ((hi as u64) << 32) | lo as u64; + } + } + } + + #[inline] + pub fn set_rtc_lo(&mut self, value: u32) { + unsafe { (*RTC::ptr()).rtclo.write(|w| w.bits(value)) }; + } + + #[inline] + pub fn set_rtc_hi(&mut self, value: u32) { + unsafe { (*RTC::ptr()).rtchi.write(|w| w.bits(value)) }; + } + + pub fn set_rtc(&mut self, value: u64) { + self.set_rtc_hi((value >> 32) as u32); + self.set_rtc_lo(value as u32); + } + + #[inline] + pub fn rtccmp(&self) -> u32 { + unsafe { (*RTC::ptr()).rtccmp.read().bits() } + } + + #[inline] + pub fn set_rtccmp(&mut self, value: u32) { + unsafe { (*RTC::ptr()).rtccmp.write(|w| w.bits(value)) }; + } +} From f6528c31a4d30bc6f1dffffa9c735c36253d38a7 Mon Sep 17 00:00:00 2001 From: David Craven Date: Wed, 28 Mar 2018 17:55:16 +0200 Subject: [PATCH 026/315] Define TX, RX, TxPin, RxPin types. --- src/lib.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1f1b543..230902a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ pub extern crate e310x_hal as hal; -pub use serial::{TX, RX, tx_rx}; -pub use led::{RED, GREEN, BLUE, rgb}; +pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; +pub use led::{RED, GREEN, BLUE, rgb, Led}; pub mod serial { //! Single UART hooked up to FTDI @@ -16,21 +16,27 @@ pub mod serial { //! - Rx = Pin 16 use hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; use hal::gpio::{IOF0, NoInvert}; + use hal::serial::{Tx, Rx}; + use hal::e310x::UART0; /// UART0 TX Pin - pub type TX = Pin17>; + pub type TxPin = Pin17>; /// UART0 RX Pin - pub type RX = Pin16>; + pub type RxPin = Pin16>; + /// UART0 TX + pub type TX = Tx; + /// UART0 RX + pub type RX = Rx; /// Return TX, RX pins. pub fn tx_rx( tx: Pin17, rx: Pin16, out_xor: &mut OUT_XOR, iof_sel: &mut IOF_SEL, iof_en: &mut IOF_EN - ) -> (TX, RX) + ) -> (TxPin, RxPin) { - let tx: TX = tx.into_iof0(out_xor, iof_sel, iof_en); - let rx: RX = rx.into_iof0(out_xor, iof_sel, iof_en); + let tx: TxPin = tx.into_iof0(out_xor, iof_sel, iof_en); + let rx: RxPin = rx.into_iof0(out_xor, iof_sel, iof_en); (tx, rx) } } From 1d9b94aea0f12cdec03866bb02d0c65189cf36e7 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 31 Mar 2018 11:45:38 +0200 Subject: [PATCH 027/315] Add wdog driver. --- src/lib.rs | 1 + src/prelude.rs | 1 + src/wdog.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/wdog.rs diff --git a/src/lib.rs b/src/lib.rs index abfc34b..74ef819 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,3 +25,4 @@ pub mod rtc; pub mod serial; pub mod stdout; pub mod time; +pub mod wdog; diff --git a/src/prelude.rs b/src/prelude.rs index 23c1264..86bfadb 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,3 +10,4 @@ pub use plic::PlicExt as _e310x_hal_plic_PlicExt; pub use rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use serial::{Serial, Tx, Rx}; pub use time::U32Ext as _e310x_hal_time_U32Ext; +pub use wdog::WdogExt as _e310x_hal_wdog_WdogExt; diff --git a/src/wdog.rs b/src/wdog.rs new file mode 100644 index 0000000..2adf74a --- /dev/null +++ b/src/wdog.rs @@ -0,0 +1,97 @@ +//! Watchdog +#![allow(missing_docs)] +use e310x::WDOG; + +pub trait WdogExt { + fn configure(self) -> WdogCfg; +} + +impl WdogExt for WDOG { + fn configure(self) -> WdogCfg { + WdogCfg { + _0: (), + enable: false, + awake: false, + reset: false, + zero_cmp: false, + scale: 0, + } + } +} + +pub struct WdogCfg { + _0: (), + enable: bool, + awake: bool, + reset: bool, + zero_cmp: bool, + scale: u8, +} + +impl WdogCfg { + pub fn enable(mut self) -> Self { + self.enable = true; + self + } + + pub fn enable_awake(mut self) -> Self { + self.awake = true; + self + } + + pub fn enable_reset(mut self) -> Self { + self.reset = true; + self + } + + pub fn enable_zero_cmp(mut self) -> Self { + self.zero_cmp = true; + self + } + + pub fn scale(mut self, scale: u8) -> Self { + self.scale = scale; + self + } + + pub fn freeze(self) -> Wdog { + unsafe { + (*WDOG::ptr()).wdogkey.write(|w| w.bits(0x51F15E)); + (*WDOG::ptr()).wdogcfg.write(|w| w + .scale().bits(self.scale) + .rsten().bit(self.reset) + .zerocmp().bit(self.zero_cmp) + .enalways().bit(self.enable) + .encoreawake().bit(self.awake)); + } + Wdog { _0: () } + } +} + +pub struct Wdog { + _0: (), +} + +impl Wdog { + #[inline] + fn unlock(&mut self) { + unsafe { (*WDOG::ptr()).wdogkey.write(|w| w.bits(0x51F15E)) }; + } + + pub fn is_pending(&self) -> bool { + unsafe { (*WDOG::ptr()).wdogcfg.read().cmpip().bit() } + } + + pub fn feed(&mut self) { + self.unlock(); + unsafe { (*WDOG::ptr()).wdogfeed.write(|w| w.bits(0xD09F00D)) }; + } + + pub fn cmp(&self) -> u16 { + unsafe { (*WDOG::ptr()).wdogcmp.read().value().bits() } + } + + pub fn set_cmp(&mut self, value: u16) { + unsafe { (*WDOG::ptr()).wdogcmp.write(|w| w.value().bits(value)) }; + } +} From ebff3a99ce008384fe10ff73455cb5f50d68a806 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 31 Mar 2018 11:46:47 +0200 Subject: [PATCH 028/315] Update plic driver. --- src/plic.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/plic.rs b/src/plic.rs index 68e83cf..19db4f8 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -93,6 +93,12 @@ pub struct PlicParts { impl PlicExt for PLIC { fn split(self) -> PlicParts { + // Disable all interrupts by default + unsafe { + self.enable[0].write(|w| w.bits(0)); + self.enable[1].write(|w| w.bits(0)); + } + PlicParts { mext: MEXT { _0: () }, threshold: THRESHOLD { _0: () }, @@ -174,10 +180,15 @@ pub struct CLAIM { impl CLAIM { /// Claims the interrupt with the highest priority. - pub fn claim(&mut self) -> Interrupt { + pub fn claim(&mut self) -> Option { // NOTE: Atomic read with side effects. - unsafe { - Interrupt::try_from((*PLIC::ptr()).claim.read().bits() as u8).unwrap() + let intr = unsafe { (*PLIC::ptr()).claim.read().bits() }; + + // If no interrupt is pending return None + if intr == 0 { + None + } else { + Some(Interrupt::try_from(intr as u8).unwrap()) } } @@ -202,7 +213,7 @@ pub struct INTERRUPT { } impl INTERRUPT { - /// Enable WDOG interrupt. + /// Enable IRQ interrupt. #[inline] pub fn enable(&mut self) { // NOTE: should use atomic operations @@ -212,7 +223,7 @@ impl INTERRUPT { } } - /// Disable WDOG interrupt. + /// Disable IRQ interrupt. #[inline] pub fn disable(&mut self) { // NOTE: should use atomic operations @@ -222,7 +233,7 @@ impl INTERRUPT { } } - /// Returns true when WDOG interrupt is pending. + /// Returns true when IRQ interrupt is pending. pub fn is_pending(&self) -> bool { // NOTE: Atomic write without side effects. let pending = unsafe { @@ -240,7 +251,7 @@ impl INTERRUPT { enabled.bits() & self.mask == self.mask } - /// Returns the priority of the WDOG interrupt. + /// Returns the priority of the IRQ interrupt. pub fn priority(&self) -> Priority { // NOTE: Atomic read without side effects. let priority = unsafe { @@ -249,7 +260,7 @@ impl INTERRUPT { Priority::from(priority.bits()).unwrap() } - /// Sets the priority of the WDOG interrupt. + /// Sets the priority of the IRQ interrupt. pub fn set_priority(&mut self, priority: Priority) { // NOTE: Atomic write without side effects. unsafe { From e4c34fbb7916364c1470c404f2e9aebfc2644c9c Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 31 Mar 2018 11:47:02 +0200 Subject: [PATCH 029/315] Update rtc driver. --- src/rtc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtc.rs b/src/rtc.rs index 0475135..73216df 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -69,12 +69,12 @@ impl Rtc { } #[inline] - pub fn set_rtc_hi(&mut self, value: u32) { - unsafe { (*RTC::ptr()).rtchi.write(|w| w.bits(value)) }; + pub fn set_rtc_hi(&mut self, value: u16) { + unsafe { (*RTC::ptr()).rtchi.write(|w| w.value().bits(value)) }; } pub fn set_rtc(&mut self, value: u64) { - self.set_rtc_hi((value >> 32) as u32); + self.set_rtc_hi((value >> 32) as u16); self.set_rtc_lo(value as u32); } From e956d95c5c8e2c57abd8d5e024aeb9bfa9fd52e4 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 31 Mar 2018 11:47:23 +0200 Subject: [PATCH 030/315] Update serial driver. --- src/serial.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 6c8265c..5ecdf64 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -21,7 +21,6 @@ use nb; use e310x::UART0; use clock::Clocks; use gpio::{IOF0, gpio0}; -use plic::{INTERRUPT, IrqUart0}; use time::Bps; // FIXME these should be "closed" traits @@ -35,10 +34,9 @@ unsafe impl TxPin for gpio0::Pin17> {} unsafe impl RxPin for gpio0::Pin16> {} /// Serial abstraction -pub struct Serial { +pub struct Serial { uart: USART, pins: PINS, - intr: INTERRUPT, } /// Serial receiver @@ -53,17 +51,16 @@ pub struct Tx { macro_rules! hal { ($( - $UARTX:ident: $uartX:ident, $IRQ:ty + $UARTX:ident: $uartX:ident )+) => { $( - impl Serial<$UARTX, (TX, RX), $IRQ> { + impl Serial<$UARTX, (TX, RX)> { /// Configures a UART peripheral to provide serial communication pub fn $uartX( uart: $UARTX, pins: (TX, RX), baud_rate: Bps, clocks: Clocks, - intr: INTERRUPT<$IRQ> ) -> Self where TX: TxPin<$UARTX>, @@ -75,21 +72,21 @@ macro_rules! hal { uart.txctrl.write(|w| w.enable().bit(true)); uart.rxctrl.write(|w| w.enable().bit(true)); - Serial { uart, pins, intr } + Serial { uart, pins } } /// Starts listening for an interrupt event - pub fn listen(&mut self) { - self.uart.ie.write(|w| w.txwm().bit(true) + pub fn listen(self) -> Self { + self.uart.ie.write(|w| w.txwm().bit(false) .rxwm().bit(true)); - self.intr.enable(); + self } /// Starts listening for an interrupt event - pub fn unlisten(&mut self) { - self.intr.disable(); + pub fn unlisten(self) -> Self { self.uart.ie.write(|w| w.txwm().bit(false) .rxwm().bit(false)); + self } /// Splits the `Serial` abstraction into a transmitter and a @@ -160,5 +157,5 @@ macro_rules! hal { } hal! { - UART0: uart0, IrqUart0 + UART0: uart0 } From dc100b463bcfea3fb79cfee4815568eeaf023746 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 11 Aug 2018 17:58:32 +0200 Subject: [PATCH 031/315] A unified contributing experience. --- .github/CODEOWNERS | 1 + .github/bors.toml | 4 ++++ .travis.yml | 50 ++++++++++++++++++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.md | 37 ++++++++++++++++++++++++++++++++++ ci/install.sh | 9 +++++++++ ci/script.sh | 9 +++++++++ 6 files changed, 110 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/bors.toml create mode 100644 .travis.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 ci/install.sh create mode 100644 ci/script.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..87f6c03 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rust-embedded/riscv \ No newline at end of file diff --git a/.github/bors.toml b/.github/bors.toml new file mode 100644 index 0000000..ca42be0 --- /dev/null +++ b/.github/bors.toml @@ -0,0 +1,4 @@ +block_labels = ["needs-decision"] +delete_merged_branches = true +required_approvals = 1 +status = ["continuous-integration/travis-ci/push"] diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a3c9cf2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,50 @@ +language: rust + +matrix: + include: + #- env: TARGET=x86_64-unknown-linux-gnu + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=riscv32imac-unknown-none-elf + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=x86_64-unknown-linux-gnu + # rust: beta + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=riscv32imac-unknown-none-elf + # rust: beta + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=x86_64-unknown-linux-gnu + rust: nightly + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=riscv32imac-unknown-none-elf + rust: nightly + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + +before_install: set -e + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cargo +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +branches: + only: + - master + - staging + - trying + +notifications: + email: + on_success: never diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a22c4f6 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [RISCV team](https://github.com/rust-embedded/wg#the-riscv-team) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISCV team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-riscv-team diff --git a/ci/install.sh b/ci/install.sh new file mode 100644 index 0000000..3c41921 --- /dev/null +++ b/ci/install.sh @@ -0,0 +1,9 @@ +set -euxo pipefail + +main() { + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/ci/script.sh b/ci/script.sh new file mode 100644 index 0000000..f5f3877 --- /dev/null +++ b/ci/script.sh @@ -0,0 +1,9 @@ +set -euxo pipefail + +main() { + cargo check --target $TARGET + + cargo check --target $TARGET --no-default-features +} + +main From 0b99c6933dd4d0c9d503f5be92bfa1a5832c575c Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 10:42:35 +0200 Subject: [PATCH 032/315] Bump version and update deps. --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ea8c211..9226858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.1.0" +version = "0.2.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -11,9 +11,9 @@ license = "ISC" [dependencies] embedded-hal = { version = "0.1.2", features = ["unproven"] } nb = "0.1.1" -riscv = { path = "../riscv" } -riscv-rt = { path = "../riscv-rt" } -e310x = { path = "../e310x", features = ["rt"] } +riscv = "0.3.0" +riscv-rt = "0.3.0" +e310x = { version = "0.2.0", features = ["rt"] } [features] default = ["pll", "hfxosc", "lfaltclk"] From 22f43b27eb06c43183fa127bca438c660e03c359 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 10:44:14 +0200 Subject: [PATCH 033/315] Update README. --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2002120..ae98557 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ [![crates.io](https://img.shields.io/crates/d/e310x-hal.svg)](https://crates.io/crates/e310x-hal) [![crates.io](https://img.shields.io/crates/v/e310x-hal.svg)](https://crates.io/crates/e310x-hal) +[![Build Status](https://travis-ci.org/riscv-rust/e310x-hal.svg?branch=master)](https://travis-ci.org/riscv-rust/e310x-hal) # `e310x-hal` > HAL for the E310x family of microcontrollers. +This project is developed and maintained by the [RISCV team][team]. + ## [Documentation](https://docs.rs/crate/e310x-hal) ## License -Copyright 2017 David Craven + +Copyright 2018 [RISCV team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice @@ -21,3 +25,12 @@ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [RISCV team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-riscv-team From d74f25b75b9e7d539d3e56e04a228ad8e1a9c4c2 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sat, 11 Aug 2018 17:58:32 +0200 Subject: [PATCH 034/315] A unified contributing experience. --- .github/CODEOWNERS | 1 + .github/bors.toml | 4 ++++ .travis.yml | 50 ++++++++++++++++++++++++++++++++++++++++++++++ CODE_OF_CONDUCT.md | 37 ++++++++++++++++++++++++++++++++++ ci/install.sh | 9 +++++++++ ci/script.sh | 7 +++++++ 6 files changed, 108 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/bors.toml create mode 100644 .travis.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 ci/install.sh create mode 100644 ci/script.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..87f6c03 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rust-embedded/riscv \ No newline at end of file diff --git a/.github/bors.toml b/.github/bors.toml new file mode 100644 index 0000000..ca42be0 --- /dev/null +++ b/.github/bors.toml @@ -0,0 +1,4 @@ +block_labels = ["needs-decision"] +delete_merged_branches = true +required_approvals = 1 +status = ["continuous-integration/travis-ci/push"] diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a3c9cf2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,50 @@ +language: rust + +matrix: + include: + #- env: TARGET=x86_64-unknown-linux-gnu + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=riscv32imac-unknown-none-elf + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=x86_64-unknown-linux-gnu + # rust: beta + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + #- env: TARGET=riscv32imac-unknown-none-elf + # rust: beta + # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=x86_64-unknown-linux-gnu + rust: nightly + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=riscv32imac-unknown-none-elf + rust: nightly + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + +before_install: set -e + +install: + - bash ci/install.sh + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cargo +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +branches: + only: + - master + - staging + - trying + +notifications: + email: + on_success: never diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a22c4f6 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,37 @@ +# The Rust Code of Conduct + +## Conduct + +**Contact**: [RISCV team](https://github.com/rust-embedded/wg#the-riscv-team) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISCV team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + +These are the policies for upholding our community's standards of conduct. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[team]: https://github.com/rust-embedded/wg#the-riscv-team diff --git a/ci/install.sh b/ci/install.sh new file mode 100644 index 0000000..3c41921 --- /dev/null +++ b/ci/install.sh @@ -0,0 +1,9 @@ +set -euxo pipefail + +main() { + if [ $TARGET != x86_64-unknown-linux-gnu ]; then + rustup target add $TARGET + fi +} + +main diff --git a/ci/script.sh b/ci/script.sh new file mode 100644 index 0000000..9e10e88 --- /dev/null +++ b/ci/script.sh @@ -0,0 +1,7 @@ +set -euxo pipefail + +main() { + cargo check --target $TARGET +} + +main From 84b30b9e47579840ba76d50143405ab9e6ba76c5 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 10:58:03 +0200 Subject: [PATCH 035/315] Bump version. Update url and deps. --- Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c4b3a34..7beb076 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hifive" -version = "0.1.0" -repository = "https://github.com/dvc94ch/hifive" +version = "0.2.0" +repository = "https://github.com/riscv-rust/hifive" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] description = "Board support crate for hifive and lofive boards." @@ -9,6 +9,6 @@ keywords = ["riscv", "register", "peripheral"] license = "ISC" [dependencies] -riscv = { path = "../riscv" } -riscv-rt = { path = "../riscv-rt" } -e310x-hal = { path = "../e310x-hal", features = ["pll", "hfxosc", "lfaltclk"] } +riscv = "0.3.0" +riscv-rt = "0.3.0" +e310x-hal = { version = "0.2.0", features = ["pll", "hfxosc", "lfaltclk"] } From 0b447ecf51c8f055bae47bf2c8bb4a37d0313560 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 10:59:08 +0200 Subject: [PATCH 036/315] Update README. --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d5dfb2..ea95c3e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![crates.io](https://img.shields.io/crates/d/hifive.svg)](https://crates.io/crates/hifive) [![crates.io](https://img.shields.io/crates/v/hifive.svg)](https://crates.io/crates/hifive) +[![Build Status](https://travis-ci.org/riscv-rust/hifive.svg?branch=master)](https://travis-ci.org/riscv-rust/hifive) # `hifive` @@ -8,7 +9,8 @@ ## [Documentation](https://docs.rs/crate/hifive) ## License -Copyright 2017 David Craven + +Copyright 2018 [RISCV team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice @@ -21,3 +23,12 @@ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], the maintainer of this crate, the [RISCV team][team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[team]: https://github.com/rust-embedded/wg#the-riscv-team From ef355cc8ba4835f18d5cbef856700793748d7b76 Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 11:09:11 +0200 Subject: [PATCH 037/315] Update embedded-hal. --- Cargo.toml | 2 +- src/gpio.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9226858..7c9439e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["riscv", "e310", "hal"] license = "ISC" [dependencies] -embedded-hal = { version = "0.1.2", features = ["unproven"] } +embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" riscv = "0.3.0" riscv-rt = "0.3.0" diff --git a/src/gpio.rs b/src/gpio.rs index dab0b09..b251426 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -62,7 +62,7 @@ macro_rules! gpio { pub mod $gpiox { use core::marker::PhantomData; - use hal::digital::{InputPin, OutputPin}; + use hal::digital::{InputPin, OutputPin, StatefulOutputPin}; use e310x::{$gpioy, $GPIOX}; use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, NoInvert, Output, PullUp, Regular}; @@ -363,17 +363,19 @@ macro_rules! gpio { } } - impl OutputPin for $PXi> { - fn is_high(&self) -> bool { - !self.is_low() + impl StatefulOutputPin for $PXi> { + fn is_set_high(&self) -> bool { + !self.is_set_low() } - fn is_low(&self) -> bool { + fn is_set_low(&self) -> bool { // NOTE unsafe atomic read with no side effects let gpio = unsafe { &*$GPIOX::ptr() }; gpio.value.read().$pxi().bit() } + } + impl OutputPin for $PXi> { fn set_high(&mut self) { // FIXME has to read register first // use atomics From e7f33961069c6c18c0cf41eea001039da629667e Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 12 Aug 2018 11:16:54 +0200 Subject: [PATCH 038/315] Implement ToggleableOutputPin. --- src/gpio.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index b251426..bb32089 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -62,7 +62,8 @@ macro_rules! gpio { pub mod $gpiox { use core::marker::PhantomData; - use hal::digital::{InputPin, OutputPin, StatefulOutputPin}; + use hal::digital::{InputPin, OutputPin, StatefulOutputPin, + ToggleableOutputPin}; use e310x::{$gpioy, $GPIOX}; use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, NoInvert, Output, PullUp, Regular}; @@ -391,9 +392,9 @@ macro_rules! gpio { } } - impl $PXi> { + impl ToggleableOutputPin for $PXi> { /// Toggles the pin state. - pub fn toggle(&mut self) { + fn toggle(&mut self) { // FIXME: has to read register first // use atomics let gpio = unsafe { &*$GPIOX::ptr() }; From 3d64ae0d6ebe0498b3b3cb7db8e43fd2b8acc125 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 24 Feb 2019 22:31:39 +0300 Subject: [PATCH 039/315] Update dependencies --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7c9439e..cf57b78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,9 @@ license = "ISC" [dependencies] embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" -riscv = "0.3.0" -riscv-rt = "0.3.0" -e310x = { version = "0.2.0", features = ["rt"] } +riscv = "0.4.0" +riscv-rt = "0.4.0" +e310x = { version = "0.3.0", features = ["rt"] } [features] default = ["pll", "hfxosc", "lfaltclk"] From 799ce525f2da966d49960f7720a010d365e5c62c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 24 Feb 2019 22:31:55 +0300 Subject: [PATCH 040/315] Do not use TryFrom --- src/lib.rs | 1 - src/plic.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 74ef819..5ef3deb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ #![deny(warnings)] #![feature(never_type)] #![no_std] -#![feature(try_from)] extern crate embedded_hal as hal; #[macro_use] diff --git a/src/plic.rs b/src/plic.rs index 19db4f8..e1fb067 100644 --- a/src/plic.rs +++ b/src/plic.rs @@ -1,5 +1,4 @@ //! Plic -use core::convert::TryFrom; use core::marker::PhantomData; use riscv::register::{mie, mip}; use riscv::interrupt::Nr; From 943f3019f19824bfd7827381f13547c1df20b79b Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 24 Feb 2019 22:40:03 +0300 Subject: [PATCH 041/315] Use Void instead of ! --- Cargo.toml | 1 + src/lib.rs | 2 +- src/serial.rs | 11 ++++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cf57b78..f583760 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ nb = "0.1.1" riscv = "0.4.0" riscv-rt = "0.4.0" e310x = { version = "0.3.0", features = ["rt"] } +void = { version = "1.0.2", default-features = false } [features] default = ["pll", "hfxosc", "lfaltclk"] diff --git a/src/lib.rs b/src/lib.rs index 5ef3deb..5d8935a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,12 +5,12 @@ #![deny(missing_docs)] #![deny(warnings)] -#![feature(never_type)] #![no_std] extern crate embedded_hal as hal; #[macro_use] extern crate nb; +extern crate void; extern crate riscv; pub extern crate e310x; diff --git a/src/serial.rs b/src/serial.rs index 5ecdf64..055b53d 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -17,6 +17,7 @@ use core::marker::PhantomData; use hal::serial; use nb; +use void::Void; use e310x::UART0; use clock::Clocks; @@ -109,9 +110,9 @@ macro_rules! hal { } impl serial::Read for Rx<$UARTX> { - type Error = !; + type Error = Void; - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { // NOTE(unsafe) atomic read with no side effects let rxdata = unsafe { (*$UARTX::ptr()).rxdata.read() }; @@ -124,9 +125,9 @@ macro_rules! hal { } impl serial::Write for Tx<$UARTX> { - type Error = !; + type Error = Void; - fn flush(&mut self) -> nb::Result<(), !> { + fn flush(&mut self) -> nb::Result<(), Void> { // NOTE(unsafe) atomic read with no side effects let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; @@ -137,7 +138,7 @@ macro_rules! hal { } } - fn write(&mut self, byte: u8) -> nb::Result<(), !> { + fn write(&mut self, byte: u8) -> nb::Result<(), Void> { // NOTE(unsafe) atomic read with no side effects let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; From f33a2c58c1dbe0a11cf71720bbbfe0f7e4e274db Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 26 Feb 2019 12:50:11 +0300 Subject: [PATCH 042/315] Check build on stable --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index a3c9cf2..d870f85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,14 @@ matrix: rust: nightly if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + - env: TARGET=x86_64-unknown-linux-gnu + rust: stable + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=riscv32imac-unknown-none-elf + rust: stable + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + before_install: set -e install: From 894991b1aafb0996999d7ad21dbf83baa6f5e4df Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 26 Feb 2019 21:53:57 +0300 Subject: [PATCH 043/315] Rewrite clock::AonClk Now external clock frequency is passed as function argument. "aonclk" renamed to "lfclk" according to the datasheet. --- Cargo.toml | 3 +-- build.rs | 6 ----- src/clock.rs | 68 +++++++++++++++++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f583760..c5e6857 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ e310x = { version = "0.3.0", features = ["rt"] } void = { version = "1.0.2", default-features = false } [features] -default = ["pll", "hfxosc", "lfaltclk"] +default = ["pll", "hfxosc"] pll = [] hfxosc = [] -lfaltclk = [] \ No newline at end of file diff --git a/build.rs b/build.rs index 5a4afec..9318ad0 100644 --- a/build.rs +++ b/build.rs @@ -23,20 +23,14 @@ fn external_clock_frequency() { let mut f = File::create(&dest_path).expect("Could not create file"); let hfxosc_freq = option_env!("BOARD_HFXOSC_FREQ").unwrap_or("16000000"); - let lfaltclk_freq = option_env!("BOARD_LFALTCLK_FREQ").unwrap_or("32768"); let hfxosc_freq: u32 = str::parse(hfxosc_freq) .expect("Could not parse BOARD_HFXOSC_FREQ"); - let lfaltclk_freq: u32 = str::parse(lfaltclk_freq) - .expect("Could not parse BOARD_LFALTCLK_FREQ"); writeln!(&mut f, "const BOARD_HFXOSC_FREQ: u32 = {};", hfxosc_freq) .expect("Could not write file"); - writeln!(&mut f, "const BOARD_LFALTCLK_FREQ: u32 = {};", lfaltclk_freq) - .expect("Could not write file"); println!("cargo:rerun-if-env-changed=BOARD_HFXOSC_FREQ"); - println!("cargo:rerun-if-env-changed=BOARD_LFALTCLK_FREQ"); } fn main() { diff --git a/src/clock.rs b/src/clock.rs index cc6ed7f..23b3054 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -43,16 +43,8 @@ impl PrciExt for PRCI { impl AonExt for AONCLK { fn constrain(self) -> AonClk { - if cfg!(feature = "lfaltclk") { - AonClk { - lfaltclk: true, - freq: Hertz(BOARD_LFALTCLK_FREQ), - } - } else { - AonClk { - lfaltclk: false, - freq: Hertz(32_768), - } + AonClk { + lfaltclk: None, } } } @@ -236,24 +228,52 @@ impl CoreClk { } } -/// Constrained AONCLK peripheral +/// Constrained `AONCLK` peripheral pub struct AonClk { - lfaltclk: bool, - freq: Hertz, + lfaltclk: Option, } impl AonClk { - /// Freeze aonclk configuration. + /// Uses `LFALTCLK` (external low-frequency clock) instead of `LFROSC` (internal ring oscillator) as the clock source. + pub fn use_external>(mut self, freq: F) -> Self { + let hz: Hertz = freq.into(); + assert!(hz.0 < 500_000); + + self.lfaltclk = Some(hz); + self + } + + /// Freezes low-frequency clock configuration, making it effective pub(crate) fn freeze(self) -> Hertz { let aonclk = unsafe { &*AONCLK::ptr() }; - // Use external real time oscillator. - if self.lfaltclk { + if let Some(freq) = self.lfaltclk { + // Use external oscillator. + // Disable unused LFROSC to save power. aonclk.lfrosccfg.write(|w| w.enable().bit(false)); - } - self.freq + freq + } else { + // Use internal oscillator. + + let trim = 16; + let div = 4; // LFROSC/5 + + // Configure LFROSC + aonclk.lfrosccfg.write(|w| { + unsafe { + w.bits(trim << 16) // TODO: replace this with trim() + .div().bits(div) + .enable().bit(true) + } + }); + + // Wait for LFROSC to stabilize + while !aonclk.lfrosccfg.read().ready().bit_is_set() {} + + Hertz(32_768) // It's not so accurate: ≈30 kHz according to the datasheet + } } } @@ -264,15 +284,15 @@ impl AonClk { #[derive(Clone, Copy)] pub struct Clocks { coreclk: Hertz, - aonclk: Hertz, + lfclk: Hertz, } impl Clocks { /// Freezes the coreclk and aonclk frequencies. pub fn freeze(coreclk: CoreClk, aonclk: AonClk, mtime: &MTIME) -> Self { let coreclk = coreclk.freeze(mtime); - let aonclk = aonclk.freeze(); - Clocks { coreclk, aonclk } + let lfclk = aonclk.freeze(); + Clocks { coreclk, lfclk } } /// Returns the frozen coreclk frequency @@ -280,9 +300,9 @@ impl Clocks { self.coreclk } - /// Returns the frozen aonclk frequency - pub fn aonclk(&self) -> Hertz { - self.aonclk + /// Returns the frozen lfclk frequency + pub fn lfclk(&self) -> Hertz { + self.lfclk } /// Measure the coreclk frequency by counting the number of aonclk ticks. From 54b78b1fa2d0ba3a29206dbe259a1a1c9520d734 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 27 Feb 2019 16:11:42 +0300 Subject: [PATCH 044/315] Make MTIME shared --- src/clint.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/clint.rs b/src/clint.rs index 9c5a5fa..8cb78c5 100644 --- a/src/clint.rs +++ b/src/clint.rs @@ -25,9 +25,7 @@ pub trait ClintExt { } /// Opaque MTIME register -pub struct MTIME { - _0: (), -} +pub struct MTIME; impl MTIME { /// Read mtime register. @@ -180,7 +178,7 @@ impl ClintExt for CLINT { fn split(self) -> ClintParts { ClintParts { mtimecmp: MTIMECMP { _0: () }, - mtime: MTIME { _0: () }, + mtime: MTIME, mcycle: MCYCLE { _0: () }, minstret: MINSTRET { _0: () }, mtimer: MTIMER { _0: () }, From 36798b396488281ce56adc2090b81e7adf750fd0 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 27 Feb 2019 16:12:23 +0300 Subject: [PATCH 045/315] Do not pass MTIME everywhere --- src/clock.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 23b3054..5ea804f 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -83,11 +83,11 @@ impl CoreClk { } /// Freezes the clock frequencies. - pub(crate) fn freeze(mut self, mtime: &MTIME) -> Hertz { + pub(crate) fn freeze(mut self) -> Hertz { if self.pll { - unsafe { self.use_hfpll(mtime); } + unsafe { self.use_hfpll(); } } else if self.hfxosc { - unsafe { self.use_hfxosc(mtime); } + unsafe { self.use_hfxosc(); } } else { unsafe { self.use_hfrosc(); } } @@ -124,10 +124,10 @@ impl CoreClk { } /// Use external oscillator with bypassed pll. - unsafe fn use_hfxosc(&mut self, mtime: &MTIME) { + unsafe fn use_hfxosc(&mut self) { let prci = &*PRCI::ptr(); - self.init_pll(mtime, |_, w| { + self.init_pll(|_, w| { // bypass PLL w.bypass().bit(true) // select HFXOSC @@ -144,10 +144,10 @@ impl CoreClk { /// NOTE: By trimming the internal clock to 12MHz /// and using r=1, f=64, q=2 the maximum frequency /// of 384MHz can be reached. - unsafe fn use_hfpll(&mut self, mtime: &MTIME) { + unsafe fn use_hfpll(&mut self) { let prci = &*PRCI::ptr(); - self.init_pll(mtime, |_, w| { + self.init_pll(|_, w| { // bypass PLL w.bypass().bit(false) // select HFXOSC @@ -184,9 +184,10 @@ impl CoreClk { }*/ /// Wait for the pll to lock. - fn wait_for_lock(&self, mtime: &MTIME) { + fn wait_for_lock(&self) { let prci = unsafe { &*PRCI::ptr() }; // NOTE: reading mtime should always be safe. + let mtime = MTIME; // Won't lock when bypassed and will loop forever if !prci.pllcfg.read().bypass().bit_is_set() { @@ -202,7 +203,7 @@ impl CoreClk { } } - unsafe fn init_pll(&mut self, mtime: &MTIME, pllcfg: F, plloutdiv: G) + unsafe fn init_pll(&mut self, pllcfg: F, plloutdiv: G) where for<'w> F: FnOnce(&prci::pllcfg::R, &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, @@ -220,7 +221,7 @@ impl CoreClk { prci.pllcfg.modify(pllcfg); prci.plloutdiv.write(plloutdiv); // Wait for PLL lock - self.wait_for_lock(mtime); + self.wait_for_lock(); // Switch to PLL prci.pllcfg.modify(|_, w| { w.sel().bit(true) @@ -289,8 +290,8 @@ pub struct Clocks { impl Clocks { /// Freezes the coreclk and aonclk frequencies. - pub fn freeze(coreclk: CoreClk, aonclk: AonClk, mtime: &MTIME) -> Self { - let coreclk = coreclk.freeze(mtime); + pub fn freeze(coreclk: CoreClk, aonclk: AonClk) -> Self { + let coreclk = coreclk.freeze(); let lfclk = aonclk.freeze(); Clocks { coreclk, lfclk } } @@ -306,7 +307,8 @@ impl Clocks { } /// Measure the coreclk frequency by counting the number of aonclk ticks. - fn _measure_coreclk(&self, min_ticks: u64, mtime: &MTIME, mcycle: &MCYCLE) -> Hertz { + fn _measure_coreclk(&self, min_ticks: u64, mcycle: &MCYCLE) -> Hertz { + let mtime = MTIME; interrupt::free(|_| { // Don't start measuring until we see an mtime tick while mtime.mtime() == mtime.mtime() {} @@ -331,10 +333,10 @@ impl Clocks { } /// Measure the coreclk frequency by counting the number of aonclk ticks. - pub fn measure_coreclk(&self, mtime: &MTIME, mcycle: &MCYCLE) -> Hertz { + pub fn measure_coreclk(&self, mcycle: &MCYCLE) -> Hertz { // warm up I$ - self._measure_coreclk(1, mtime, mcycle); + self._measure_coreclk(1, mcycle); // measure for real - self._measure_coreclk(10, mtime, mcycle) + self._measure_coreclk(10, mcycle) } } From fae603193d29a2c155432dc24d30edc490efbf75 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 18:12:15 +0300 Subject: [PATCH 046/315] Rewrite clock::CoreClk Now external and desired clock frequencies are passed as function arguments. --- Cargo.toml | 5 - build.rs | 17 --- src/clock.rs | 391 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 231 insertions(+), 182 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c5e6857..0a73e04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,3 @@ riscv = "0.4.0" riscv-rt = "0.4.0" e310x = { version = "0.3.0", features = ["rt"] } void = { version = "1.0.2", default-features = false } - -[features] -default = ["pll", "hfxosc"] -pll = [] -hfxosc = [] diff --git a/build.rs b/build.rs index 9318ad0..3cd9cd1 100644 --- a/build.rs +++ b/build.rs @@ -17,24 +17,7 @@ fn memory_linker_script() { println!("cargo:rerun-if-changed=memory.x"); } -fn external_clock_frequency() { - let out_dir = env::var("OUT_DIR").expect("No out dir"); - let dest_path = Path::new(&out_dir).join("constants.rs"); - let mut f = File::create(&dest_path).expect("Could not create file"); - - let hfxosc_freq = option_env!("BOARD_HFXOSC_FREQ").unwrap_or("16000000"); - - let hfxosc_freq: u32 = str::parse(hfxosc_freq) - .expect("Could not parse BOARD_HFXOSC_FREQ"); - - writeln!(&mut f, "const BOARD_HFXOSC_FREQ: u32 = {};", hfxosc_freq) - .expect("Could not write file"); - - println!("cargo:rerun-if-env-changed=BOARD_HFXOSC_FREQ"); -} - fn main() { memory_linker_script(); - external_clock_frequency(); println!("cargo:rerun-if-changed=build.rs"); } diff --git a/src/clock.rs b/src/clock.rs index 5ea804f..38bfdd6 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,12 +1,21 @@ //! Clock configuration -use e310x::{prci, PRCI, AONCLK}; +use e310x::{PRCI, AONCLK}; use clint::{MCYCLE, MTIME}; use riscv::interrupt; use time::Hertz; -/// const BOARD_HFXOSC_FREQ: u32 -/// const BOARD_LFALTCLK_FREQ: u32 -include!(concat!(env!("OUT_DIR"), "/constants.rs")); + +const PLLREF_MIN: u32 = 6_000_000; +const PLLREF_MAX: u32 = 48_000_000; +const REFR_MIN: u32 = 6_000_000; +const REFR_MAX: u32 = 12_000_000; +const VCO_MIN: u32 = 384_000_000; +const VCO_MAX: u32 = 768_000_000; +const PLLOUT_MIN: u32 = 48_000_000; +const PLLOUT_MAX: u32 = 384_000_000; +const DIVOUT_MIN: u32 = 375_000; +const DIVOUT_MAX: u32 = 384_000_000; + /// PrciExt trait extends `PRCI` peripheral. pub trait PrciExt { @@ -24,19 +33,9 @@ pub trait AonExt { impl PrciExt for PRCI { fn constrain(self) -> CoreClk { - if cfg!(feature = "hfxosc") { - CoreClk { - hfxosc: true, - pll: false, - freq: Hertz(BOARD_HFXOSC_FREQ), - } - } else { - CoreClk { - hfxosc: false, - pll: false, - // Default after reset - freq: Hertz(13_800_000), - } + CoreClk { + hfxosc: None, + coreclk: Hertz(13_800_000), // Default after reset } } } @@ -49,183 +48,255 @@ impl AonExt for AONCLK { } } -/// Constrainted PRCI peripheral +/// Constrainted `PRCI` peripheral pub struct CoreClk { - hfxosc: bool, - pll: bool, - freq: Hertz, + hfxosc: Option, + coreclk: Hertz, } impl CoreClk { - /// Use external clock. Requires feature hfxosc and BOARD_HFXOSC_FREQ - /// should be set at build time if the external oscillator is not 16MHz. - #[cfg(feature = "hfxosc")] - pub fn use_external(mut self) -> Self { - self.hfxosc = true; - self.freq = Hertz(BOARD_HFXOSC_FREQ); - self - } + /// Uses `HFXOSC` (external oscillator) instead of `HFROSC` (internal ring oscillator) as the clock source. + pub fn use_external>(mut self, freq: F) -> Self { + let hz: Hertz = freq.into(); + assert!(hz.0 < 20_000_000); - /// Use internal clock. Sets frequency to 13.8MHz. - pub fn use_internal(mut self) -> Self { - self.hfxosc = false; - self.freq = Hertz(13_800_000); + self.hfxosc = Some(hz); self } - /// Use pll. Sets frequency to 256MHz. Requires feature pll. - /// NOTE: Assumes an external 16MHz oscillator is available. - #[cfg(feature = "pll")] - pub fn use_pll(mut self) -> Self { - self.pll = true; - self.freq = Hertz(256_000_000); + /// Sets the desired frequency for the `coreclk` clock + pub fn coreclk>(mut self, freq: F) -> Self { + self.coreclk = freq.into(); self } - /// Freezes the clock frequencies. - pub(crate) fn freeze(mut self) -> Hertz { - if self.pll { - unsafe { self.use_hfpll(); } - } else if self.hfxosc { - unsafe { self.use_hfxosc(); } + /// Freezes high-frequency clock configuration, making it effective + pub(crate) fn freeze(self) -> Hertz { + // Assume `psdclkbypass_n` is not used + + if let Some(freq) = self.hfxosc { + self.configure_with_external(freq) } else { - unsafe { self.use_hfrosc(); } + self.configure_with_internal() } - - self.freq } - /// Use internal oscillator with bypassed pll. - unsafe fn use_hfrosc(&mut self) { - let prci = &*PRCI::ptr(); - - // Enable HFROSC - prci.hfrosccfg.write(|w| { - w.enable().bit(true) - // It is OK to change this even if we are running off of it. - // Reset them to default values. (13.8MHz) - .div().bits(4) - .trim().bits(16) - }); - // Wait for HFROSC to stabilize - while !prci.hfrosccfg.read().ready().bit_is_set() {} - // Switch to HFROSC - prci.pllcfg.modify(|_, w| { - w.sel().bit(false) - }); - // Bypass PLL to save power - prci.pllcfg.modify(|_, w| { - w.bypass().bit(true) - // Select HFROSC as PLL ref to disable HFXOSC later - .refsel().bit(false) - }); - // Disable HFXOSC to save power. - prci.hfxosccfg.write(|w| w.enable().bit(false)); - } + /// Configures clock generation system with external oscillator + fn configure_with_external(self, source_freq: Hertz) -> Hertz { + let prci = unsafe { &*PRCI::ptr() }; - /// Use external oscillator with bypassed pll. - unsafe fn use_hfxosc(&mut self) { - let prci = &*PRCI::ptr(); + // Enable HFXOSC + prci.hfxosccfg.write(|w| w.enable().bit(true)); - self.init_pll(|_, w| { - // bypass PLL - w.bypass().bit(true) - // select HFXOSC - .refsel().bit(true) - }, |w| w.divby1().bit(true)); - // Disable HFROSC to save power - prci.hfrosccfg.write(|w| w.enable().bit(false)); - } + // Wait for HFXOSC to stabilize + while !prci.hfxosccfg.read().ready().bit_is_set() {} + + // Select HFXOSC as pllref + prci.pllcfg.modify(|_, w| w.refsel().bit(true)); + + let freq; + if source_freq.0 == self.coreclk.0 { + // Use external oscillator with bypassed PLL + freq = source_freq; + + // Bypass PLL + prci.pllcfg.modify(|_, w| w.bypass().bit(true)); + + // Bypass divider + prci.plloutdiv.write(|w| w.divby1().bit(true)); + } else { + // Use external oscillator with PLL + + // Configure PLL and divider + freq = self.configure_pll(source_freq, self.coreclk); + } + + // Switch to PLL + prci.pllcfg.modify(|_, w| w.sel().bit(true)); - /// Use external oscillator with pll. Sets PLL - /// r=2, f=64, q=2 values to maximum allowable - /// for a 16MHz reference clock. Output frequency - /// is 16MHz / 2 * 64 / 2 = 256MHz. - /// NOTE: By trimming the internal clock to 12MHz - /// and using r=1, f=64, q=2 the maximum frequency - /// of 384MHz can be reached. - unsafe fn use_hfpll(&mut self) { - let prci = &*PRCI::ptr(); - - self.init_pll(|_, w| { - // bypass PLL - w.bypass().bit(false) - // select HFXOSC - .refsel().bit(true) - // bits = r - 1 - .pllr().bits(1) - // bits = f / 2 - 1 - .pllf().bits(31) - // bits = q=2 -> 1, q=4 -> 2, q=8 -> 3 - .pllq().bits(1) - }, |w| w.divby1().bit(true)); // Disable HFROSC to save power prci.hfrosccfg.write(|w| w.enable().bit(false)); + + freq } - /* - /// Compute PLL multiplier. - fn pll_mult(&self) -> u32 { + /// Configures clock generation system with internal oscillator + fn configure_with_internal(self) -> Hertz { let prci = unsafe { &*PRCI::ptr() }; - let pllcfg = prci.pllcfg.read(); - let plloutdiv = prci.plloutdiv.read(); + let hfrosc_freq = self.configure_hfrosc(); - let r = pllcfg.pllr().bits() as u32 + 1; - let f = (pllcfg.pllf().bits() as u32 + 1) * 2; - let q = [2, 4, 8][pllcfg.pllq().bits() as usize - 1]; + let freq; + if hfrosc_freq.0 == self.coreclk.0 { + // Use internal oscillator with bypassed PLL + freq = hfrosc_freq; - let div = match plloutdiv.divby1().bit() { - true => 1, - false => (plloutdiv.div().bits() as u32 + 1) * 2, - }; + // Switch to HFROSC, bypass PLL to save power + prci.pllcfg.modify(|_, w| w + .sel().bit(false) + .bypass().bit(true) + ); - f / r / q / div - }*/ + // + prci.pllcfg.modify(|_, w| w.bypass().bit(true)); + } else { + // Use internal oscillator with PLL - /// Wait for the pll to lock. - fn wait_for_lock(&self) { - let prci = unsafe { &*PRCI::ptr() }; - // NOTE: reading mtime should always be safe. - let mtime = MTIME; + // Configure PLL and divider + freq = self.configure_pll(hfrosc_freq, self.coreclk); + + // Switch to PLL + prci.pllcfg.modify(|_, w| w.sel().bit(true)); - // Won't lock when bypassed and will loop forever - if !prci.pllcfg.read().bypass().bit_is_set() { - // Wait for PLL Lock - // Note that the Lock signal can be glitchy. - // Need to wait 100 us - // RTC is running at 32kHz. - // So wait 4 ticks of RTC. - let time = mtime.mtime() + 4; - while mtime.mtime() < time {} - // Now it is safe to check for PLL Lock - while !prci.pllcfg.read().lock().bit_is_set() {} } + + // Disable HFXOSC to save power + prci.hfxosccfg.write(|w| w.enable().bit(false)); + + freq } - unsafe fn init_pll(&mut self, pllcfg: F, plloutdiv: G) - where - for<'w> F: FnOnce(&prci::pllcfg::R, - &'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W, - for<'w> G: FnOnce(&'w mut prci::plloutdiv::W) -> &'w mut prci::plloutdiv::W, - { - let prci = &*PRCI::ptr(); - // Make sure we are running of internal clock - // before configuring the PLL. - self.use_hfrosc(); - // Enable HFXOSC - prci.hfxosccfg.write(|w| w.enable().bit(true)); - // Wait for HFXOSC to stabilize - while !prci.hfxosccfg.read().ready().bit_is_set() {} + /// Configures internal high-frequency oscillator (`HFROSC`) + fn configure_hfrosc(&self) -> Hertz { + let prci = unsafe { &*PRCI::ptr() }; + + // TODO: use trim value from OTP + + // Configure HFROSC to 13.8 MHz + prci.hfrosccfg.write(|w| unsafe { w + .div().bits(4) + .trim().bits(16) + .enable().bit(true) + }); + + // Wait for HFROSC to stabilize + while !prci.hfrosccfg.read().ready().bit_is_set() {} + + Hertz(13_800_000) + } + + /// Configures PLL and PLL Output Divider + /// The resulting frequency may differ by 0-2% from the requested + fn configure_pll(&self, pllref_freq: Hertz, divout_freq: Hertz) -> Hertz { + let pllref_freq = pllref_freq.0; + assert!(PLLREF_MIN <= pllref_freq && pllref_freq <= PLLREF_MAX); + + let divout_freq = divout_freq.0; + assert!(DIVOUT_MIN <= divout_freq && divout_freq <= DIVOUT_MAX); + + // Calculate PLL Output Divider settings + let divider_div; + let divider_bypass; + + let d = PLLOUT_MAX / divout_freq; + if d > 1 { + divider_bypass = false; + + if d > 128 { + divider_div = (128 / 2) - 1; + } else { + divider_div = (d / 2) - 1; + } + } else { + divider_div = 0; + divider_bypass = true; + } + + // Calculate pllout frequency + let d = if divider_bypass { + 1 + } else { + 2 * (divider_div + 1) + }; + let pllout_freq = divout_freq * d; + assert!(PLLOUT_MIN <= pllout_freq && pllout_freq <= PLLOUT_MAX); + + // Calculate PLL R ratio + let r = match pllref_freq { + 24_000_000...48_000_000 => 4, + 18_000_000...24_000_000 => 3, + 12_000_000...18_000_000 => 2, + 6_000_000...12_000_000 => 1, + _ => unreachable!(), + }; + + // Calculate refr frequency + let refr_freq = pllref_freq / r; + assert!(REFR_MIN <= refr_freq && refr_freq <= REFR_MAX); + + // Calculate PLL Q ratio + let q = match pllout_freq { + 192_000_000...384_000_000 => 2, + 96_000_000...192_000_000 => 4, + 48_000_000...96_000_000 => 8, + _ => unreachable!(), + }; + + // Calculate the desired vco frequency + let target_vco_freq = pllout_freq * q; + assert!(VCO_MIN <= target_vco_freq && target_vco_freq <= VCO_MAX); + + // Calculate PLL F ratio + let f = target_vco_freq / refr_freq; + assert!(f <= 128); + + // Choose the best F ratio + let f_lo = (f / 2) * 2; // F must be a multiple of 2 + let vco_lo = refr_freq * f_lo; + let f_hi = f_lo + 2; + let vco_hi = refr_freq * f_hi; + let (f, vco_freq) = if (f_hi <= 128 && vco_hi <= VCO_MAX) && (target_vco_freq as i32 - vco_hi as i32).abs() < (target_vco_freq as i32 - vco_lo as i32).abs() { + (f_hi, vco_hi) + } else { + (f_lo, vco_lo) + }; + assert!(VCO_MIN <= vco_freq && vco_freq <= VCO_MAX); + + // Calculate actual pllout frequency + let pllout_freq = vco_freq / q; + assert!(PLLOUT_MIN <= pllout_freq && pllout_freq <= PLLOUT_MAX); + + // Calculate actual divout frequency + let divout_freq = pllout_freq / d; + assert!(DIVOUT_MIN <= divout_freq && divout_freq <= DIVOUT_MAX); + + // Calculate bit-values + let r: u8 = (r - 1) as u8; + let f: u8 = (f / 2 - 1) as u8; + let q: u8 = match q { + 2 => 0b01, + 4 => 0b10, + 8 => 0b11, + _ => unreachable!(), + }; + // Configure PLL - prci.pllcfg.modify(pllcfg); - prci.plloutdiv.write(plloutdiv); - // Wait for PLL lock - self.wait_for_lock(); - // Switch to PLL - prci.pllcfg.modify(|_, w| { - w.sel().bit(true) + let prci = unsafe { &*PRCI::ptr() }; + prci.pllcfg.modify(|_, w| unsafe { w + .pllr().bits(r) + .pllf().bits(f) + .pllq().bits(q) + .bypass().bit(false) }); + + // Configure PLL Output Divider + prci.plloutdiv.write(|w| unsafe { w + .div().bits(divider_div as u8) + .divby1().bit(divider_bypass) + }); + + // Wait for PLL Lock + // Note that the Lock signal can be glitchy. + // Need to wait 100 us + // RTC is running at 32kHz. + // So wait 4 ticks of RTC. + let mtime = MTIME; + let time = mtime.mtime() + 4; + while mtime.mtime() < time {} + // Now it is safe to check for PLL Lock + while !prci.pllcfg.read().lock().bit_is_set() {} + + Hertz(divout_freq) } } From cb184b8276ca511c0d1ba0494594fab1ab5825be Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 18:22:28 +0300 Subject: [PATCH 047/315] Use tlclk clock for UART --- src/clock.rs | 7 +++++++ src/serial.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/clock.rs b/src/clock.rs index 38bfdd6..c68f723 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -372,6 +372,13 @@ impl Clocks { self.coreclk } + /// Returns the frozen tlclk frequency + pub fn tlclk(&self) -> Hertz { + // For the FE310-G000, the TileLink bus clock (tlclk) is fixed to be + // the same as the processor core clock (coreclk) + self.coreclk + } + /// Returns the frozen lfclk frequency pub fn lfclk(&self) -> Hertz { self.lfclk diff --git a/src/serial.rs b/src/serial.rs index 055b53d..145a2f5 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -67,7 +67,7 @@ macro_rules! hal { TX: TxPin<$UARTX>, RX: RxPin<$UARTX>, { - let div = clocks.coreclk().0 / baud_rate.0 + 1; + let div = clocks.tlclk().0 / baud_rate.0 + 1; unsafe { uart.div.write(|w| w.bits(div)); } uart.txctrl.write(|w| w.enable().bit(true)); From 8b23957383bc54f54b2c111980353f9ad9a76283 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 19:44:04 +0300 Subject: [PATCH 048/315] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0a73e04..24e5999 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.2.0" +version = "0.3.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 528d89b05f652b00eb7ae7f3a60413af1911be76 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 24 Feb 2019 22:45:22 +0300 Subject: [PATCH 049/315] Update dependencies --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7beb076..afdfcc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,6 @@ keywords = ["riscv", "register", "peripheral"] license = "ISC" [dependencies] -riscv = "0.3.0" -riscv-rt = "0.3.0" -e310x-hal = { version = "0.2.0", features = ["pll", "hfxosc", "lfaltclk"] } +riscv = "0.4.0" +riscv-rt = "0.4.0" +e310x-hal = "0.3.0" From 37aee31b15d8ca142d85fb043e4f6c30d82caec2 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 20:20:58 +0300 Subject: [PATCH 050/315] Move led and serial modules to separate files --- src/led.rs | 85 +++++++++++++++++++++++++++++++++++ src/lib.rs | 121 +------------------------------------------------- src/serial.rs | 29 ++++++++++++ 3 files changed, 116 insertions(+), 119 deletions(-) create mode 100644 src/led.rs create mode 100644 src/serial.rs diff --git a/src/led.rs b/src/led.rs new file mode 100644 index 0000000..e4df1f8 --- /dev/null +++ b/src/led.rs @@ -0,0 +1,85 @@ +//! On-board user LEDs +//! +//! - Red = Pin 22 +//! - Green = Pin 19 +//! - Blue = Pin 21 +use hal::prelude::*; +use hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, + OUT_XOR, IOF_EN}; +use hal::gpio::{Output, Regular, Invert}; + +/// Red LED +pub type RED = Pin22>>; + +/// Green LED +pub type GREEN = Pin19>>; + +/// Blue LED +pub type BLUE = Pin21>>; + +/// Returns RED, GREEN and BLUE LEDs. +pub fn rgb( + red: Pin22, green: Pin19, blue: Pin21, + output_en: &mut OUTPUT_EN, drive: &mut DRIVE, + out_xor: &mut OUT_XOR, iof_en: &mut IOF_EN +) -> (RED, GREEN, BLUE) +{ + let red: RED = red.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + let green: GREEN = green.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + let blue: BLUE = blue.into_inverted_output( + output_en, + drive, + out_xor, + iof_en, + ); + (red, green, blue) +} + +/// Generic LED +pub trait Led { + /// Turns the LED off + fn off(&mut self); + + /// Turns the LED on + fn on(&mut self); +} + +impl Led for RED { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); + } + + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); + } +} + +impl Led for GREEN { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); + } + + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); + } +} + +impl Led for BLUE { + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); + } + + fn off(&mut self) { + _embedded_hal_digital_OutputPin::set_low(self); + } +} diff --git a/src/lib.rs b/src/lib.rs index 230902a..88e2aca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,122 +9,5 @@ pub extern crate e310x_hal as hal; pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; pub use led::{RED, GREEN, BLUE, rgb, Led}; -pub mod serial { - //! Single UART hooked up to FTDI - //! - //! - Tx = Pin 17 - //! - Rx = Pin 16 - use hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; - use hal::gpio::{IOF0, NoInvert}; - use hal::serial::{Tx, Rx}; - use hal::e310x::UART0; - - /// UART0 TX Pin - pub type TxPin = Pin17>; - /// UART0 RX Pin - pub type RxPin = Pin16>; - /// UART0 TX - pub type TX = Tx; - /// UART0 RX - pub type RX = Rx; - - /// Return TX, RX pins. - pub fn tx_rx( - tx: Pin17, rx: Pin16, - out_xor: &mut OUT_XOR, iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN - ) -> (TxPin, RxPin) - { - let tx: TxPin = tx.into_iof0(out_xor, iof_sel, iof_en); - let rx: RxPin = rx.into_iof0(out_xor, iof_sel, iof_en); - (tx, rx) - } -} - -pub mod led { - //! On-board user LEDs - //! - //! - Red = Pin 22 - //! - Green = Pin 19 - //! - Blue = Pin 21 - use hal::prelude::*; - use hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, - OUT_XOR, IOF_EN}; - use hal::gpio::{Output, Regular, Invert}; - - /// Red LED - pub type RED = Pin22>>; - - /// Green LED - pub type GREEN = Pin19>>; - - /// Blue LED - pub type BLUE = Pin21>>; - - /// Returns RED, GREEN and BLUE LEDs. - pub fn rgb( - red: Pin22, green: Pin19, blue: Pin21, - output_en: &mut OUTPUT_EN, drive: &mut DRIVE, - out_xor: &mut OUT_XOR, iof_en: &mut IOF_EN - ) -> (RED, GREEN, BLUE) - { - let red: RED = red.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); - let green: GREEN = green.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); - let blue: BLUE = blue.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); - (red, green, blue) - } - - /// Generic LED - pub trait Led { - /// Turns the LED off - fn off(&mut self); - - /// Turns the LED on - fn on(&mut self); - } - - impl Led for RED { - fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); - } - - fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); - } - } - - impl Led for GREEN { - fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); - } - - fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); - } - } - - impl Led for BLUE { - fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); - } - - fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); - } - } -} +pub mod serial; +pub mod led; diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 0000000..cd2aca2 --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,29 @@ +//! Single UART hooked up to FTDI +//! +//! - Tx = Pin 17 +//! - Rx = Pin 16 +use hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; +use hal::gpio::{IOF0, NoInvert}; +use hal::serial::{Tx, Rx}; +use hal::e310x::UART0; + +/// UART0 TX Pin +pub type TxPin = Pin17>; +/// UART0 RX Pin +pub type RxPin = Pin16>; +/// UART0 TX +pub type TX = Tx; +/// UART0 RX +pub type RX = Rx; + +/// Return TX, RX pins. +pub fn tx_rx( + tx: Pin17, rx: Pin16, + out_xor: &mut OUT_XOR, iof_sel: &mut IOF_SEL, + iof_en: &mut IOF_EN +) -> (TxPin, RxPin) +{ + let tx: TxPin = tx.into_iof0(out_xor, iof_sel, iof_en); + let rx: RxPin = rx.into_iof0(out_xor, iof_sel, iof_en); + (tx, rx) +} From 7d207bf5201bd51128ed3805771b2c15bd3abfd2 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 21:08:00 +0300 Subject: [PATCH 051/315] Board-specific clock configuration --- Cargo.toml | 7 +++++++ src/clock.rs | 37 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 45 insertions(+) create mode 100644 src/clock.rs diff --git a/Cargo.toml b/Cargo.toml index afdfcc5..ba4b344 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,10 @@ license = "ISC" riscv = "0.4.0" riscv-rt = "0.4.0" e310x-hal = "0.3.0" + +[features] +board-hifive1 = [] +board-lofive = [] + +[package.metadata.docs.rs] +features = ['board-hifive1'] diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..027f397 --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,37 @@ +//! Board-specific clock configuration + +#[cfg(any(feature = "board-hifive1", feature = "board-lofive"))] +use hal::{ + e310x::{PRCI, AONCLK}, + clock::{Clocks, PrciExt, AonExt}, + time::Hertz, +}; + +#[cfg(feature = "board-hifive1")] +/// Configures clock generation system. +/// +/// For HiFive1 board external oscillators are enabled for both high-frequency and low-frequency clocks. +pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { + let coreclk = prci.constrain(); + let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); + + let aonclk = aonclk.constrain(); + let aonclk = aonclk.use_external(Hertz(32_768)); + + Clocks::freeze(coreclk, aonclk) +} + +#[cfg(feature = "board-lofive")] +/// Configures clock generation system. +/// +/// For LoFive board external oscillator is enabled for high-frequency clock. +/// For low-frequency clock internal oscillator is used. +pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { + let coreclk = prci.constrain(); + let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); + + let aonclk = aonclk.constrain(); + let aonclk = aonclk.use_external(Hertz(32_768)); + + Clocks::freeze(coreclk, aonclk) +} diff --git a/src/lib.rs b/src/lib.rs index 88e2aca..d0a8c15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,3 +11,4 @@ pub use led::{RED, GREEN, BLUE, rgb, Led}; pub mod serial; pub mod led; +pub mod clock; From d114030a8c032468bd5d94c2e83dd8c3e66be7db Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 21:11:46 +0300 Subject: [PATCH 052/315] Fix board names --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ba4b344..8d28fe9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.2.0" repository = "https://github.com/riscv-rust/hifive" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] -description = "Board support crate for hifive and lofive boards." +description = "Board support crate for HiFive1 and LoFive boards" keywords = ["riscv", "register", "peripheral"] license = "ISC" diff --git a/README.md b/README.md index ea95c3e..d5e3b0f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # `hifive` -> Board support crate for hifive and lofive boards. +> Board support crate for HiFive1 and LoFive boards ## [Documentation](https://docs.rs/crate/hifive) diff --git a/src/lib.rs b/src/lib.rs index d0a8c15..3774644 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Board support crate for the Hifive +//! Board support crate for HiFive1 and LoFive boards #![deny(missing_docs)] #![deny(warnings)] From 7081be1d6c415f90c7118539f2992c2125effb71 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 21:35:21 +0300 Subject: [PATCH 053/315] Feature-gate led module --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3774644..bff1628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,10 @@ pub extern crate e310x_hal as hal; pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; +#[cfg(feature = "board-hifive1")] pub use led::{RED, GREEN, BLUE, rgb, Led}; pub mod serial; +#[cfg(feature = "board-hifive1")] pub mod led; pub mod clock; From a3522e880ee59586b500fb2d8b016163a5ae4c42 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 21:52:41 +0300 Subject: [PATCH 054/315] Tidy code --- src/led.rs | 16 ++++++++-------- src/lib.rs | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/led.rs b/src/led.rs index e4df1f8..1f321e1 100644 --- a/src/led.rs +++ b/src/led.rs @@ -55,31 +55,31 @@ pub trait Led { } impl Led for RED { - fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); - } - fn off(&mut self) { _embedded_hal_digital_OutputPin::set_low(self); } -} -impl Led for GREEN { fn on(&mut self) { _embedded_hal_digital_OutputPin::set_high(self); } +} +impl Led for GREEN { fn off(&mut self) { _embedded_hal_digital_OutputPin::set_low(self); } -} -impl Led for BLUE { fn on(&mut self) { _embedded_hal_digital_OutputPin::set_high(self); } +} +impl Led for BLUE { fn off(&mut self) { _embedded_hal_digital_OutputPin::set_low(self); } + + fn on(&mut self) { + _embedded_hal_digital_OutputPin::set_high(self); + } } diff --git a/src/lib.rs b/src/lib.rs index bff1628..6850839 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,11 +6,11 @@ pub extern crate e310x_hal as hal; -pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; +pub mod clock; #[cfg(feature = "board-hifive1")] -pub use led::{RED, GREEN, BLUE, rgb, Led}; - +pub mod led; pub mod serial; + #[cfg(feature = "board-hifive1")] -pub mod led; -pub mod clock; +pub use led::{RED, GREEN, BLUE, rgb, Led}; +pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; From 478c21d4b58d56e3d852e1529a3602cb5e59cfe7 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 22:11:19 +0300 Subject: [PATCH 055/315] CI: build with features enabled --- ci/script.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/script.sh b/ci/script.sh index 9e10e88..bbb89ce 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -2,6 +2,8 @@ set -euxo pipefail main() { cargo check --target $TARGET + cargo check --target $TARGET --features 'board-hifive1' + cargo check --target $TARGET --features 'board-lofive' } main From e19b6e7a24ab18996e4b5cb0ace67de23a6243af Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 22:11:54 +0300 Subject: [PATCH 056/315] Check build on stable --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index a3c9cf2..d870f85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,14 @@ matrix: rust: nightly if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + - env: TARGET=x86_64-unknown-linux-gnu + rust: stable + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + + - env: TARGET=riscv32imac-unknown-none-elf + rust: stable + if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) + before_install: set -e install: From 4f039f981e897b0601a19e4e6e6a15161d10f5a6 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 22:19:00 +0300 Subject: [PATCH 057/315] Rename crate to 'hifive1' --- Cargo.toml | 4 ++-- README.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8d28fe9..abca714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "hifive" +name = "hifive1" version = "0.2.0" -repository = "https://github.com/riscv-rust/hifive" +repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] description = "Board support crate for HiFive1 and LoFive boards" diff --git a/README.md b/README.md index d5e3b0f..22456d8 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -[![crates.io](https://img.shields.io/crates/d/hifive.svg)](https://crates.io/crates/hifive) -[![crates.io](https://img.shields.io/crates/v/hifive.svg)](https://crates.io/crates/hifive) -[![Build Status](https://travis-ci.org/riscv-rust/hifive.svg?branch=master)](https://travis-ci.org/riscv-rust/hifive) +[![crates.io](https://img.shields.io/crates/d/hifive1.svg)](https://crates.io/crates/hifive1) +[![crates.io](https://img.shields.io/crates/v/hifive1.svg)](https://crates.io/crates/hifive1) +[![Build Status](https://travis-ci.org/riscv-rust/hifive1.svg?branch=master)](https://travis-ci.org/riscv-rust/hifive1) -# `hifive` +# `hifive1` > Board support crate for HiFive1 and LoFive boards -## [Documentation](https://docs.rs/crate/hifive) +## [Documentation](https://docs.rs/crate/hifive1) ## License From b18173217f97d82161ea00cd2a1d3aef8ffc6ec0 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 28 Feb 2019 22:19:30 +0300 Subject: [PATCH 058/315] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index abca714..cde1503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.2.0" +version = "0.3.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 8789f37dd6df95b3042296f9715623f51fb051e1 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 11 Mar 2019 22:00:59 +0300 Subject: [PATCH 059/315] Replace USART with UART --- src/serial.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 145a2f5..6dbf578 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -35,19 +35,19 @@ unsafe impl TxPin for gpio0::Pin17> {} unsafe impl RxPin for gpio0::Pin16> {} /// Serial abstraction -pub struct Serial { - uart: USART, +pub struct Serial { + uart: UART, pins: PINS, } /// Serial receiver pub struct Rx { - _usart: PhantomData, + _usar: PhantomData, } /// Serial transmitter pub struct Tx { - _usart: PhantomData, + _usar: PhantomData, } macro_rules! hal { @@ -95,15 +95,15 @@ macro_rules! hal { pub fn split(self) -> (Tx<$UARTX>, Rx<$UARTX>) { ( Tx { - _usart: PhantomData, + _usar: PhantomData, }, Rx { - _usart: PhantomData, + _usar: PhantomData, }, ) } - /// Releases the USART peripheral and associated pins + /// Releases the UART peripheral and associated pins pub fn free(self) -> ($UARTX, (TX, RX)) { (self.uart, self.pins) } From 74cb57a8645388a1b4eb2a6f00bd5a5bfd7372b5 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 11 Mar 2019 22:04:11 +0300 Subject: [PATCH 060/315] Fix UART divisor calculation --- src/serial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index 6dbf578..a74fdd2 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -67,7 +67,7 @@ macro_rules! hal { TX: TxPin<$UARTX>, RX: RxPin<$UARTX>, { - let div = clocks.tlclk().0 / baud_rate.0 + 1; + let div = clocks.tlclk().0 / baud_rate.0 - 1; unsafe { uart.div.write(|w| w.bits(div)); } uart.txctrl.write(|w| w.enable().bit(true)); From ce141133315db6a64afc37954968cab55a79d2c9 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 11 Mar 2019 22:12:50 +0300 Subject: [PATCH 061/315] Bump version (0.3.1) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 24e5999..d7ac335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.3.0" +version = "0.3.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 363c1a19fca485f75dabc905d2a617dee27627b5 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 12 Mar 2019 20:14:54 +0300 Subject: [PATCH 062/315] Remove unused 'riscv-rt' dependency --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d7ac335..a6646d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,5 @@ license = "ISC" embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" riscv = "0.4.0" -riscv-rt = "0.4.0" e310x = { version = "0.3.0", features = ["rt"] } void = { version = "1.0.2", default-features = false } From 7b560645542cec401b1184309e70eead4b7e4acf Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 12 Mar 2019 20:16:54 +0300 Subject: [PATCH 063/315] Update dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6646d7..b84abf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,6 @@ license = "ISC" [dependencies] embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" -riscv = "0.4.0" -e310x = { version = "0.3.0", features = ["rt"] } +riscv = "0.5.0" +e310x = { version = "0.4.0", features = ["rt"] } void = { version = "1.0.2", default-features = false } From 8367388bb3c1502e42c544a9fc0d34233eaa6eb8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 12 Mar 2019 20:32:13 +0300 Subject: [PATCH 064/315] Update to edition 2018 --- Cargo.toml | 1 + src/clock.rs | 4 ++-- src/gpio.rs | 2 +- src/lib.rs | 8 +------- src/prelude.rs | 22 +++++++++++----------- src/serial.rs | 8 ++++---- src/stdout.rs | 3 ++- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b84abf2..b6a4188 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "HAL for the E310x family of microcontrollers." keywords = ["riscv", "e310", "hal"] license = "ISC" +edition = "2018" [dependencies] embedded-hal = { version = "0.2.1", features = ["unproven"] } diff --git a/src/clock.rs b/src/clock.rs index c68f723..87b2233 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,8 +1,8 @@ //! Clock configuration use e310x::{PRCI, AONCLK}; -use clint::{MCYCLE, MTIME}; +use crate::clint::{MCYCLE, MTIME}; use riscv::interrupt; -use time::Hertz; +use crate::time::Hertz; const PLLREF_MIN: u32 = 6_000_000; diff --git a/src/gpio.rs b/src/gpio.rs index bb32089..3e5549b 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -62,7 +62,7 @@ macro_rules! gpio { pub mod $gpiox { use core::marker::PhantomData; - use hal::digital::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::{$gpioy, $GPIOX}; use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, diff --git a/src/lib.rs b/src/lib.rs index 5d8935a..320e266 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,13 +7,7 @@ #![deny(warnings)] #![no_std] -extern crate embedded_hal as hal; -#[macro_use] -extern crate nb; -extern crate void; - -extern crate riscv; -pub extern crate e310x; +pub use e310x; pub mod clint; pub mod clock; diff --git a/src/prelude.rs b/src/prelude.rs index 86bfadb..e2d2e8b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,13 +1,13 @@ //! Prelude -pub use hal::prelude::*; -pub use clint::ClintExt as _e310x_hal_clint_ClintExt; -pub use clock::Clocks; -pub use clock::PrciExt as _e310x_hal_clock_PrciExt; -pub use clock::AonExt as _e310x_hal_clock_AonExt; -pub use gpio::GpioExt as _e310x_hal_gpio_GpioExt; -pub use plic::PlicExt as _e310x_hal_plic_PlicExt; -pub use rtc::RtcExt as _e310x_hal_rtc_RtcExt; -pub use serial::{Serial, Tx, Rx}; -pub use time::U32Ext as _e310x_hal_time_U32Ext; -pub use wdog::WdogExt as _e310x_hal_wdog_WdogExt; +pub use embedded_hal::prelude::*; +pub use crate::clint::ClintExt as _e310x_hal_clint_ClintExt; +pub use crate::clock::Clocks; +pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; +pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; +pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; +pub use crate::plic::PlicExt as _e310x_hal_plic_PlicExt; +pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; +pub use crate::serial::{Serial, Tx, Rx}; +pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; +pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; diff --git a/src/serial.rs b/src/serial.rs index a74fdd2..d1cae12 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -15,14 +15,14 @@ use core::marker::PhantomData; -use hal::serial; +use embedded_hal::serial; use nb; use void::Void; use e310x::UART0; -use clock::Clocks; -use gpio::{IOF0, gpio0}; -use time::Bps; +use crate::clock::Clocks; +use crate::gpio::{IOF0, gpio0}; +use crate::time::Bps; // FIXME these should be "closed" traits /// TX pin - DO NOT IMPLEMENT THIS TRAIT diff --git a/src/stdout.rs b/src/stdout.rs index 228637b..abe2ce8 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -1,5 +1,6 @@ //! Stdout pub use core::fmt::Write; +use nb::block; /// Stdout implements the core::fmt::Write trait for hal::serial::Write /// implementations. @@ -9,7 +10,7 @@ pub struct Stdout<'p, T>(pub &'p mut T) impl<'p, T> Write for Stdout<'p, T> where - T: ::hal::serial::Write, + T: embedded_hal::serial::Write, { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { From 007ba832f0ace66a900158c13562f15b992b2915 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 19:30:50 +0300 Subject: [PATCH 065/315] Fix typo --- src/serial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index d1cae12..55934c2 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -83,7 +83,7 @@ macro_rules! hal { self } - /// Starts listening for an interrupt event + /// Stops listening for an interrupt event pub fn unlisten(self) -> Self { self.uart.ie.write(|w| w.txwm().bit(false) .rxwm().bit(false)); From 61561e17c5c8ce2888e704cf3e0ec7c18bfa0121 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:36:15 +0300 Subject: [PATCH 066/315] Fix serial docs --- src/serial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index 55934c2..060402d 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -8,10 +8,10 @@ //! - Interrupt::UART0 //! //! # UART1 +//! *Warning:* UART1 pins are not connected to package in FE310-G000 //! - TX: Pin 25 IOF0 //! - RX: Pin 24 IOF0 //! - Interrupt::UART1 -//! Pins not connected to package in E310-G000 use core::marker::PhantomData; From 9545b0d8d5fb19cff65141c03b0ea53fcf14b582 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:36:36 +0300 Subject: [PATCH 067/315] Implement SPI support --- src/lib.rs | 1 + src/spi.rs | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 src/spi.rs diff --git a/src/lib.rs b/src/lib.rs index 320e266..eaa736b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod plic; pub mod prelude; pub mod rtc; pub mod serial; +pub mod spi; pub mod stdout; pub mod time; pub mod wdog; diff --git a/src/spi.rs b/src/spi.rs new file mode 100644 index 0000000..e2747cc --- /dev/null +++ b/src/spi.rs @@ -0,0 +1,221 @@ +//! # Serial Peripheral Interface +//! +//! You can use the `FullDuplex` interface with these SPI instances +//! +//! # QSPI0 +//! - Interrupt::QSPI0 +//! +//! # QSPI1 +//! - MOSI: Pin 3 IOF0 +//! - MISO: Pin 4 IOF0 +//! - SCK: Pin 5 IOF0 +//! - SS0: Pin 2 IOF0 +//! - SS1: Pin 8 IOF0 +//! - SS2: Pin 9 IOF0 +//! - SS3: Pin 10 IOF0 +//! - Interrupt::QSPI1 +//! +//! # QSPI2 +//! *Warning:* QSPI2 pins are not connected to package in FE310-G000 +//! - MOSI: Pin 27 IOF0 +//! - MISO: Pin 28 IOF0 +//! - SCK: Pin 29 IOF0 +//! - SS: Pin 26 IOF0 +//! - Interrupt::QSPI0 + +pub use embedded_hal::spi::{Mode, Phase, Polarity}; +use crate::e310x::{QSPI0, QSPI1, QSPI2}; +use crate::gpio::{IOF0, gpio0}; +use crate::clock::Clocks; +use crate::time::Hertz; +use nb; +use void::Void; + + +/// SPI pins - DO NOT IMPLEMENT THIS TRAIT +/// +/// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) and (MOSI, MISO, SCK, SS) +pub trait Pins { + #[doc(hidden)] + const CS_INDEX: Option; +} + +/* SPI0 pins */ +impl Pins for () { + const CS_INDEX: Option = Some(0); +} + +/* SPI1 pins */ +impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>) { + const CS_INDEX: Option = None; +} + +impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin2>) { + const CS_INDEX: Option = Some(0); +} + +impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin8>) { + const CS_INDEX: Option = Some(1); +} + +impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin9>) { + const CS_INDEX: Option = Some(2); +} + +impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin10>) { + const CS_INDEX: Option = Some(3); +} + +/* SPI2 pins */ +impl Pins for (gpio0::Pin27>, gpio0::Pin28>, gpio0::Pin29>) { + const CS_INDEX: Option = None; +} + +impl Pins for (gpio0::Pin27>, gpio0::Pin28>, gpio0::Pin29>, gpio0::Pin26>) { + const CS_INDEX: Option = Some(0); +} + +/// SPI abstraction +pub struct Spi { + spi: SPI, + pins: PINS, +} + +macro_rules! hal { + ($($SPIX:ident: $spiX:ident,)+) => { + $( + impl Spi<$SPIX, PINS> { + /// Configures the SPI peripheral to operate in full duplex master mode + pub fn $spiX( + spi: $SPIX, + pins: PINS, + mode: Mode, + freq: Hertz, + clocks: Clocks, + ) -> Self + where + PINS: Pins<$SPIX>, + { + let div = clocks.tlclk().0 / (2 * freq.0) - 1; + spi.div.write(|w| unsafe { w.bits(div) }); + + let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { + spi.csid.write(|w| unsafe { w.bits(cs_index) }); + + 0 // AUTO: Assert/de-assert CS at the beginning/end of each frame + } else { + 3 // OFF: Disable hardware control of the CS pin + }; + spi.csmode.write(|w| unsafe { w.bits(cs_mode) }); + + // Set CS pin polarity to high + spi.csdef.reset(); + + // Set SPI mode + let phase = mode.phase == Phase::CaptureOnSecondTransition; + let polarity = mode.polarity == Polarity::IdleHigh; + spi.mode.write(|w| w + .phase().bit(phase) + .polarity().bit(polarity) + ); + + spi.fmt.write(|w| unsafe { w + .protocol().bits(0) // Single + .endian().clear_bit() // Transmit most-significant bit (MSB) first + .direction().rx() + .length().bits(8) + }); + + // Set watermark levels + spi.txmark.write(|w| unsafe { w.value().bits(1) }); + spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + + spi.delay0.reset(); + spi.delay1.reset(); + + Self { spi, pins } + } + + /// Sets transmit watermark level + pub fn set_tx_watermark(&mut self, value: u8) { + self.spi.txmark.write(|w| unsafe { w.value().bits(value) }); + } + + /// Sets receive watermark level + pub fn set_rx_watermark(&mut self, value: u8) { + self.spi.rxmark.write(|w| unsafe { w.value().bits(value) }); + } + + /// Returns transmit watermark event status + pub fn tx_wm_is_pending(&self) -> bool { + self.spi.ip.read().txwm().bit() + } + + /// Returns receive watermark event status + pub fn rx_wm_is_pending(&self) -> bool { + self.spi.ip.read().rxwm().bit() + } + + /// Starts listening for transmit watermark interrupt event + pub fn listen_tx_wm(&mut self) { + self.spi.ie.write(|w| w.txwm().set_bit()) + } + + /// Starts listening for receive watermark interrupt event + pub fn listen_rx_wm(&mut self) { + self.spi.ie.write(|w| w.rxwm().set_bit()) + } + + /// Stops listening for transmit watermark interrupt event + pub fn unlisten_tx_wm(&mut self) { + self.spi.ie.write(|w| w.txwm().clear_bit()) + } + + /// Stops listening for receive watermark interrupt event + pub fn unlisten_rx_wm(&mut self) { + self.spi.ie.write(|w| w.rxwm().clear_bit()) + } + + /// Releases the SPI peripheral and associated pins + pub fn free(self) -> ($SPIX, PINS) { + (self.spi, self.pins) + } + } + + impl embedded_hal::spi::FullDuplex for Spi<$SPIX, PINS> { + type Error = void::Void; + + fn read(&mut self) -> nb::Result { + let rxdata = self.spi.rxdata.read(); + + if rxdata.empty().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits()) + } + } + + fn send(&mut self, byte: u8) -> nb::Result<(), Void> { + let txdata = self.spi.txdata.read(); + + if txdata.full().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + Ok(()) + } + } + } + + impl embedded_hal::blocking::spi::transfer::Default for Spi<$SPIX, PINS> {} + + impl embedded_hal::blocking::spi::write::Default for Spi<$SPIX, PINS> {} + )+ + } +} + +hal! { + QSPI0: spi0, + QSPI1: spi1, + QSPI2: spi2, +} From 7dc2b96df258bcfd6cf7f742c237fb15635affdb Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:48:57 +0300 Subject: [PATCH 068/315] Update Travis build matrix --- .travis.yml | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index d870f85..2a869cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,15 @@ language: rust -matrix: - include: - #- env: TARGET=x86_64-unknown-linux-gnu - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +env: +- TARGET=x86_64-unknown-linux-gnu +- TARGET=riscv32imac-unknown-none-elf - #- env: TARGET=riscv32imac-unknown-none-elf - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +rust: +- nightly +- stable - #- env: TARGET=x86_64-unknown-linux-gnu - # rust: beta - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - #- env: TARGET=riscv32imac-unknown-none-elf - # rust: beta - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=x86_64-unknown-linux-gnu - rust: nightly - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=riscv32imac-unknown-none-elf - rust: nightly - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=x86_64-unknown-linux-gnu - rust: stable - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=riscv32imac-unknown-none-elf - rust: stable - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) before_install: set -e From badf9be54260591464e7459339a3fa5ee0d268aa Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:49:32 +0300 Subject: [PATCH 069/315] Remove useless 'set' commands --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a869cd..6dd1c3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,15 +11,12 @@ rust: if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) -before_install: set -e - install: - bash ci/install.sh script: - bash ci/script.sh -after_script: set +e cache: cargo before_cache: From d9bd4fdf663ef11c7b25b6a607ffd9f771827d2a Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:50:15 +0300 Subject: [PATCH 070/315] Simplify CI scripts --- .travis.yml | 4 ++-- ci/install.sh | 10 +++------- ci/script.sh | 10 +++------- 3 files changed, 8 insertions(+), 16 deletions(-) mode change 100644 => 100755 ci/install.sh mode change 100644 => 100755 ci/script.sh diff --git a/.travis.yml b/.travis.yml index 6dd1c3b..badfe86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,10 @@ if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_req install: - - bash ci/install.sh + - ci/install.sh script: - - bash ci/script.sh + - ci/script.sh cache: cargo diff --git a/ci/install.sh b/ci/install.sh old mode 100644 new mode 100755 index 3c41921..ce4ea1e --- a/ci/install.sh +++ b/ci/install.sh @@ -1,9 +1,5 @@ -set -euxo pipefail +#!/bin/bash -main() { - if [ $TARGET != x86_64-unknown-linux-gnu ]; then - rustup target add $TARGET - fi -} +set -euxo pipefail -main +rustup target add $TARGET diff --git a/ci/script.sh b/ci/script.sh old mode 100644 new mode 100755 index f5f3877..ce6c403 --- a/ci/script.sh +++ b/ci/script.sh @@ -1,9 +1,5 @@ -set -euxo pipefail - -main() { - cargo check --target $TARGET +#!/bin/bash - cargo check --target $TARGET --no-default-features -} +set -euxo pipefail -main +cargo check --target $TARGET From 135a013208f8ab76e2d6645c52f38c563c504f3c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 13 Mar 2019 20:56:14 +0300 Subject: [PATCH 071/315] Bump version (0.4.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b6a4188..9233fb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.3.1" +version = "0.4.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 28234ea42e016573663ba0adccf43d893e8e245c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 16:14:54 +0300 Subject: [PATCH 072/315] Remove unused dependencies --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cde1503..4ee1047 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,6 @@ keywords = ["riscv", "register", "peripheral"] license = "ISC" [dependencies] -riscv = "0.4.0" -riscv-rt = "0.4.0" e310x-hal = "0.3.0" [features] From dd864a1cbc068f0cc44c17a4c76cf046f13eabef Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 16:16:42 +0300 Subject: [PATCH 073/315] Update dependencies --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4ee1047..88ed22f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["riscv", "register", "peripheral"] license = "ISC" [dependencies] -e310x-hal = "0.3.0" +e310x-hal = "0.4.0" [features] board-hifive1 = [] From 25c838331503bc3c555b5874860510e43ac2054c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 17:40:03 +0300 Subject: [PATCH 074/315] Update Travis build matrix --- .travis.yml | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index d870f85..2e823ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,15 @@ language: rust -matrix: - include: - #- env: TARGET=x86_64-unknown-linux-gnu - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +env: + - TARGET=x86_64-unknown-linux-gnu + - TARGET=riscv32imac-unknown-none-elf - #- env: TARGET=riscv32imac-unknown-none-elf - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +rust: + - nightly + - stable - #- env: TARGET=x86_64-unknown-linux-gnu - # rust: beta - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) +if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - #- env: TARGET=riscv32imac-unknown-none-elf - # rust: beta - # if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=x86_64-unknown-linux-gnu - rust: nightly - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=riscv32imac-unknown-none-elf - rust: nightly - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=x86_64-unknown-linux-gnu - rust: stable - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - - env: TARGET=riscv32imac-unknown-none-elf - rust: stable - if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) before_install: set -e From e133f8ea807284680cb3a8c455b7cebfd0e780ab Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 17:41:32 +0300 Subject: [PATCH 075/315] Remove useless 'set' commands --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2e823ad..57626b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,15 +11,12 @@ rust: if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) -before_install: set -e - install: - bash ci/install.sh script: - bash ci/script.sh -after_script: set +e cache: cargo before_cache: From 93acdbd09e7f591a2d52e75e91f3ad11fd216661 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 17:42:12 +0300 Subject: [PATCH 076/315] Simplify CI scripts --- .travis.yml | 4 ++-- ci/install.sh | 10 +++------- ci/script.sh | 12 +++++------- 3 files changed, 10 insertions(+), 16 deletions(-) mode change 100644 => 100755 ci/install.sh mode change 100644 => 100755 ci/script.sh diff --git a/.travis.yml b/.travis.yml index 57626b6..8821911 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,10 @@ if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_req install: - - bash ci/install.sh + - ci/install.sh script: - - bash ci/script.sh + - ci/script.sh cache: cargo diff --git a/ci/install.sh b/ci/install.sh old mode 100644 new mode 100755 index 3c41921..b2789a8 --- a/ci/install.sh +++ b/ci/install.sh @@ -1,9 +1,5 @@ -set -euxo pipefail +#!/usr/bin/env bash -main() { - if [ $TARGET != x86_64-unknown-linux-gnu ]; then - rustup target add $TARGET - fi -} +set -euxo pipefail -main +rustup target add $TARGET diff --git a/ci/script.sh b/ci/script.sh old mode 100644 new mode 100755 index bbb89ce..31f4802 --- a/ci/script.sh +++ b/ci/script.sh @@ -1,9 +1,7 @@ -set -euxo pipefail +#!/usr/bin/env bash -main() { - cargo check --target $TARGET - cargo check --target $TARGET --features 'board-hifive1' - cargo check --target $TARGET --features 'board-lofive' -} +set -euxo pipefail -main +cargo check --target $TARGET +cargo check --target $TARGET --features 'board-hifive1' +cargo check --target $TARGET --features 'board-lofive' From bd794a7b638a5ba0a71d571c1bd87eb683152de8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 14 Mar 2019 17:48:27 +0300 Subject: [PATCH 077/315] Bump version (0.4.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 88ed22f..3f43257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.3.0" +version = "0.4.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 7c1f0296c6df82cd3fd551f614e082e772b8902e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 15 Mar 2019 15:51:19 +0300 Subject: [PATCH 078/315] Reexport SPI MODE constants --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index e2747cc..030c97c 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -23,7 +23,7 @@ //! - SS: Pin 26 IOF0 //! - Interrupt::QSPI0 -pub use embedded_hal::spi::{Mode, Phase, Polarity}; +pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::e310x::{QSPI0, QSPI1, QSPI2}; use crate::gpio::{IOF0, gpio0}; use crate::clock::Clocks; From 5bfb8b7fa0d4beb57e28166e0700e24603908312 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 15 Mar 2019 15:54:07 +0300 Subject: [PATCH 079/315] Remove structs from prelude --- src/prelude.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/prelude.rs b/src/prelude.rs index e2d2e8b..0b2ce54 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,12 +2,10 @@ pub use embedded_hal::prelude::*; pub use crate::clint::ClintExt as _e310x_hal_clint_ClintExt; -pub use crate::clock::Clocks; pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; pub use crate::plic::PlicExt as _e310x_hal_plic_PlicExt; pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; -pub use crate::serial::{Serial, Tx, Rx}; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; From baeed842de79616a4bab8c13a21481a3ab062adf Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Apr 2019 17:58:30 +0300 Subject: [PATCH 080/315] Remove memory definitions Flash size should be defined in hifive1 crate --- build.rs | 23 ----------------------- memory.x | 22 ---------------------- 2 files changed, 45 deletions(-) delete mode 100644 build.rs delete mode 100644 memory.x diff --git a/build.rs b/build.rs deleted file mode 100644 index 3cd9cd1..0000000 --- a/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::Path; - -/// Put the linker script somewhere the linker can find it. -fn memory_linker_script() { - let out_dir = env::var("OUT_DIR").expect("No out dir"); - let dest_path = Path::new(&out_dir); - let mut f = File::create(&dest_path.join("memory.x")) - .expect("Could not create file"); - - f.write_all(include_bytes!("memory.x")) - .expect("Could not write file"); - - println!("cargo:rustc-link-search={}", dest_path.display()); - println!("cargo:rerun-if-changed=memory.x"); -} - -fn main() { - memory_linker_script(); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/memory.x b/memory.x deleted file mode 100644 index c991460..0000000 --- a/memory.x +++ /dev/null @@ -1,22 +0,0 @@ -MEMORY -{ -/* NOTE K = KiBi = 1024 bytes */ -/* TODO Adjust these memory regions to match your device memory layout */ -FLASH : ORIGIN = 0x20400000, LENGTH = 512M -RAM : ORIGIN = 0x80000000, LENGTH = 16K -} - -/* This is where the call stack will be allocated. */ -/* The stack is of the full descending type. */ -/* You may want to use this variable to locate the call stack and static -variables in different memory regions. Below is shown the default value */ - -/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ - -/* You can use this symbol to customize the location of the .text section */ -/* If omitted the .text section will be placed right after the .vector_table -section */ -/* This is required only on microcontrollers that store some configuration right -after the vector table */ - -/* _stext = ORIGIN(FLASH); */ From c76ab0411dfd4f81ac0fdc95e153b4ecc9932a0c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Apr 2019 18:50:41 +0300 Subject: [PATCH 081/315] Fix typos --- src/serial.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 060402d..85b078f 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -42,12 +42,12 @@ pub struct Serial { /// Serial receiver pub struct Rx { - _usar: PhantomData, + _uart: PhantomData, } /// Serial transmitter pub struct Tx { - _usar: PhantomData, + _uart: PhantomData, } macro_rules! hal { @@ -95,10 +95,10 @@ macro_rules! hal { pub fn split(self) -> (Tx<$UARTX>, Rx<$UARTX>) { ( Tx { - _usar: PhantomData, + _uart: PhantomData, }, Rx { - _usar: PhantomData, + _uart: PhantomData, }, ) } From 1e578ff4f0b0d386091177cd19c2e11361d3ed51 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Apr 2019 18:26:09 +0300 Subject: [PATCH 082/315] Rename RISCV to RISC-V --- CODE_OF_CONDUCT.md | 4 ++-- README.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a22c4f6..fccadf9 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ ## Conduct -**Contact**: [RISCV team](https://github.com/rust-embedded/wg#the-riscv-team) +**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team) * We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. @@ -10,7 +10,7 @@ * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. * Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. * We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. -* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISCV team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. ## Moderation diff --git a/README.md b/README.md index ae98557..09f0512 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ > HAL for the E310x family of microcontrollers. -This project is developed and maintained by the [RISCV team][team]. +This project is developed and maintained by the [RISC-V team][team]. ## [Documentation](https://docs.rs/crate/e310x-hal) ## License -Copyright 2018 [RISCV team][team] +Copyright 2018 [RISC-V team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice @@ -29,7 +29,7 @@ THIS SOFTWARE. ## Code of Conduct Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [RISCV team][team], promises +Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises to intervene to uphold that code of conduct. [CoC]: CODE_OF_CONDUCT.md From 5ff3be6987caeafae109113d2e6dd611034ebd0a Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Apr 2019 18:26:56 +0300 Subject: [PATCH 083/315] Update copyright years --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09f0512..4179dab 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## License -Copyright 2018 [RISC-V team][team] +Copyright 2018-2019 [RISC-V team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice From 28571780213c42ca743fc545d8e35061f40e4c74 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Apr 2019 18:31:38 +0300 Subject: [PATCH 084/315] Rename RISCV to RISC-V --- CODE_OF_CONDUCT.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a22c4f6..fccadf9 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ ## Conduct -**Contact**: [RISCV team](https://github.com/rust-embedded/wg#the-riscv-team) +**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team) * We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. @@ -10,7 +10,7 @@ * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. * Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. * We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. -* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISCV team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. ## Moderation diff --git a/README.md b/README.md index 22456d8..f3eb4d4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## License -Copyright 2018 [RISCV team][team] +Copyright 2018 [RISC-V team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice @@ -27,7 +27,7 @@ THIS SOFTWARE. ## Code of Conduct Contribution to this crate is organized under the terms of the [Rust Code of -Conduct][CoC], the maintainer of this crate, the [RISCV team][team], promises +Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises to intervene to uphold that code of conduct. [CoC]: CODE_OF_CONDUCT.md From ca417b567795a378a17e4b1bf236253eaa429499 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Apr 2019 18:31:53 +0300 Subject: [PATCH 085/315] Update copyright years --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3eb4d4..0b85820 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## License -Copyright 2018 [RISC-V team][team] +Copyright 2018-2019 [RISC-V team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice From c3f7cd83ed94b81597da842a9b931d903a804334 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 18 May 2019 14:57:59 +0300 Subject: [PATCH 086/315] stdout: Make EOL `\r\n` instead of `\n\r` https://github.com/riscv-rust/k210-hal/pull/2 --- src/stdout.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stdout.rs b/src/stdout.rs index abe2ce8..43ad49c 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -14,12 +14,6 @@ impl<'p, T> Write for Stdout<'p, T> { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { - let res = block!(self.0.write(*byte)); - - if res.is_err() { - return Err(::core::fmt::Error); - } - if *byte == '\n' as u8 { let res = block!(self.0.write('\r' as u8)); @@ -27,6 +21,12 @@ impl<'p, T> Write for Stdout<'p, T> return Err(::core::fmt::Error); } } + + let res = block!(self.0.write(*byte)); + + if res.is_err() { + return Err(::core::fmt::Error); + } } Ok(()) } From 5862bcd7301d26e7d4b2768777166a2ec6a7ac4e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 18 May 2019 15:07:33 +0300 Subject: [PATCH 087/315] Remove #![deny(warnings)] (anti pattern) --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index eaa736b..40751fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ //! family of microcontrollers. #![deny(missing_docs)] -#![deny(warnings)] #![no_std] pub use e310x; From 3ffb1d54e9db2e1517f5348ad8015152e34744f5 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Apr 2019 18:46:58 +0300 Subject: [PATCH 088/315] Add memory definitions for HiFive1 board --- build.rs | 13 +++++++++++++ memory-hifive1.x | 15 +++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 build.rs create mode 100644 memory-hifive1.x diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b02b3a1 --- /dev/null +++ b/build.rs @@ -0,0 +1,13 @@ +use std::{env, fs}; +use std::path::PathBuf; +use std::io::Write; + +fn main() { + // Put the linker script somewhere the linker can find it + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + println!("cargo:rustc-link-search={}", out_dir.display()); + + fs::File::create(out_dir.join("memory-hifive1.x")).unwrap() + .write_all(include_bytes!("memory-hifive1.x")).unwrap(); + println!("cargo:rerun-if-changed=memory-hifive1.x"); +} diff --git a/memory-hifive1.x b/memory-hifive1.x new file mode 100644 index 0000000..cd55c70 --- /dev/null +++ b/memory-hifive1.x @@ -0,0 +1,15 @@ +INCLUDE memory-fe310.x +MEMORY +{ + FLASH : ORIGIN = 0x20000000, LENGTH = 16M +} + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +/* Skip first 4M allocated for bootloader */ +_stext = 0x20400000; From a9d87a119367c98df57f02d5557cca298f05f90f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 20 May 2019 09:42:53 +0300 Subject: [PATCH 089/315] Add memory definitions for HiFive1 Rev B board --- build.rs | 4 ++++ memory-hifive1-revb.x | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 memory-hifive1-revb.x diff --git a/build.rs b/build.rs index b02b3a1..45b0eae 100644 --- a/build.rs +++ b/build.rs @@ -10,4 +10,8 @@ fn main() { fs::File::create(out_dir.join("memory-hifive1.x")).unwrap() .write_all(include_bytes!("memory-hifive1.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1.x"); + + fs::File::create(out_dir.join("memory-hifive1-revb.x")).unwrap() + .write_all(include_bytes!("memory-hifive1-revb.x")).unwrap(); + println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); } diff --git a/memory-hifive1-revb.x b/memory-hifive1-revb.x new file mode 100644 index 0000000..e9e4bc5 --- /dev/null +++ b/memory-hifive1-revb.x @@ -0,0 +1,15 @@ +INCLUDE memory-fe310.x +MEMORY +{ + FLASH : ORIGIN = 0x20000000, LENGTH = 4M +} + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +/* Skip first 64k allocated for bootloader */ +_stext = 0x20010000; From 28479b763e8a9ee8a27a5cd0a6d7f4b3479dbe2f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 20 May 2019 11:18:39 +0300 Subject: [PATCH 090/315] Remove #![deny(warnings)] (anti-pattern) --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6850839..2fc6ca4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ //! Board support crate for HiFive1 and LoFive boards #![deny(missing_docs)] -#![deny(warnings)] #![no_std] pub extern crate e310x_hal as hal; From e371d69fed4b3ee0708a39f92fd303ccfa348df5 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 14:56:03 +0300 Subject: [PATCH 091/315] Replace Void with Infallible --- Cargo.toml | 1 - src/serial.rs | 12 ++++++------ src/spi.rs | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9233fb7..b518d54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,3 @@ embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" riscv = "0.5.0" e310x = { version = "0.4.0", features = ["rt"] } -void = { version = "1.0.2", default-features = false } diff --git a/src/serial.rs b/src/serial.rs index 85b078f..897cefc 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -14,10 +14,10 @@ //! - Interrupt::UART1 use core::marker::PhantomData; +use core::convert::Infallible; use embedded_hal::serial; use nb; -use void::Void; use e310x::UART0; use crate::clock::Clocks; @@ -110,9 +110,9 @@ macro_rules! hal { } impl serial::Read for Rx<$UARTX> { - type Error = Void; + type Error = Infallible; - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { // NOTE(unsafe) atomic read with no side effects let rxdata = unsafe { (*$UARTX::ptr()).rxdata.read() }; @@ -125,9 +125,9 @@ macro_rules! hal { } impl serial::Write for Tx<$UARTX> { - type Error = Void; + type Error = Infallible; - fn flush(&mut self) -> nb::Result<(), Void> { + fn flush(&mut self) -> nb::Result<(), Infallible> { // NOTE(unsafe) atomic read with no side effects let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; @@ -138,7 +138,7 @@ macro_rules! hal { } } - fn write(&mut self, byte: u8) -> nb::Result<(), Void> { + fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { // NOTE(unsafe) atomic read with no side effects let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; diff --git a/src/spi.rs b/src/spi.rs index 030c97c..f53803e 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -23,13 +23,13 @@ //! - SS: Pin 26 IOF0 //! - Interrupt::QSPI0 +use core::convert::Infallible; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::e310x::{QSPI0, QSPI1, QSPI2}; use crate::gpio::{IOF0, gpio0}; use crate::clock::Clocks; use crate::time::Hertz; use nb; -use void::Void; /// SPI pins - DO NOT IMPLEMENT THIS TRAIT @@ -183,9 +183,9 @@ macro_rules! hal { } impl embedded_hal::spi::FullDuplex for Spi<$SPIX, PINS> { - type Error = void::Void; + type Error = Infallible; - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { let rxdata = self.spi.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -195,7 +195,7 @@ macro_rules! hal { } } - fn send(&mut self, byte: u8) -> nb::Result<(), Void> { + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { let txdata = self.spi.txdata.read(); if txdata.full().bit_is_set() { From 548b464ea8593eea19eb935dbfb317021bbaa395 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:19:50 +0300 Subject: [PATCH 092/315] Implement digital::v2 traits --- src/gpio.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 3e5549b..b3364fa 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -61,8 +61,9 @@ macro_rules! gpio { /// GPIO pub mod $gpiox { use core::marker::PhantomData; + use core::convert::Infallible; - use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::{$gpioy, $GPIOX}; use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, @@ -353,52 +354,61 @@ macro_rules! gpio { } impl InputPin for $PXi> { - fn is_high(&self) -> bool { - !self.is_low() + type Error = Infallible; + + fn is_high(&self) -> Result { + Ok(!self.is_low()?) } - fn is_low(&self) -> bool { + fn is_low(&self) -> Result { let gpio = unsafe { &*$GPIOX::ptr() }; // NOTE unsafe atomic read with no side effects - gpio.value.read().$pxi().bit() + Ok(gpio.value.read().$pxi().bit()) } } impl StatefulOutputPin for $PXi> { - fn is_set_high(&self) -> bool { - !self.is_set_low() + fn is_set_high(&self) -> Result { + Ok(!self.is_set_low()?) } - fn is_set_low(&self) -> bool { + fn is_set_low(&self) -> Result { // NOTE unsafe atomic read with no side effects let gpio = unsafe { &*$GPIOX::ptr() }; - gpio.value.read().$pxi().bit() + Ok(gpio.value.read().$pxi().bit()) } } impl OutputPin for $PXi> { - fn set_high(&mut self) { + type Error = Infallible; + + fn set_high(&mut self) -> Result<(), Infallible> { // FIXME has to read register first // use atomics let gpio = unsafe { &*$GPIOX::ptr() }; gpio.port.modify(|_, w| w.$pxi().bit(true)); + Ok(()) } - fn set_low(&mut self) { + fn set_low(&mut self) -> Result<(), Infallible> { // FIXME: has to read register first // use atomics let gpio = unsafe { &*$GPIOX::ptr() }; gpio.port.modify(|_, w| w.$pxi().bit(false)); + Ok(()) } } impl ToggleableOutputPin for $PXi> { + type Error = Infallible; + /// Toggles the pin state. - fn toggle(&mut self) { + fn toggle(&mut self) -> Result<(), Infallible> { // FIXME: has to read register first // use atomics let gpio = unsafe { &*$GPIOX::ptr() }; gpio.port.modify(|r, w| w.$pxi().bit(!r.$pxi().bit())); + Ok(()) } } )+ From 08b2f3907c37d5eaae0d6825b66e1e7954d78d33 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:20:49 +0300 Subject: [PATCH 093/315] Update e310x dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b518d54..a74e267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,4 @@ edition = "2018" embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" riscv = "0.5.0" -e310x = { version = "0.4.0", features = ["rt"] } +e310x = { version = "0.5.0", features = ["rt"] } From 9f0371621999aa232707da73675d21f5820b8dc1 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:23:44 +0300 Subject: [PATCH 094/315] Add g002 feature --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a74e267..82aa57a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,6 @@ embedded-hal = { version = "0.2.1", features = ["unproven"] } nb = "0.1.1" riscv = "0.5.0" e310x = { version = "0.5.0", features = ["rt"] } + +[features] +g002 = ["e310x/g002"] From 5a1fbc5da82afc6544e5afe615f9ca0fa7e60108 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:24:34 +0300 Subject: [PATCH 095/315] Enable g002 feature for docs.rs --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 82aa57a..1799afe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ e310x = { version = "0.5.0", features = ["rt"] } [features] g002 = ["e310x/g002"] + +[package.metadata.docs.rs] +features = ["g002"] From 07caa85377a42885c746d948b08c7be7e0112b50 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:28:42 +0300 Subject: [PATCH 096/315] Update embedded-hal version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1799afe..eac973f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = { version = "0.2.1", features = ["unproven"] } +embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.1" riscv = "0.5.0" e310x = { version = "0.5.0", features = ["rt"] } From b7a3ec70939a865026c2b0ec42af9826331e1997 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:29:56 +0300 Subject: [PATCH 097/315] Check g002 feature in CI --- ci/script.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/script.sh b/ci/script.sh index ce6c403..c048a90 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -3,3 +3,4 @@ set -euxo pipefail cargo check --target $TARGET +cargo check --target $TARGET --features g002 From 8eab2f14966c3e88ac129968eb2c1572fde23b79 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:38:16 +0300 Subject: [PATCH 098/315] Fix deprecation warnings --- src/clock.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 87b2233..cfc1faf 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -213,10 +213,10 @@ impl CoreClk { // Calculate PLL R ratio let r = match pllref_freq { - 24_000_000...48_000_000 => 4, - 18_000_000...24_000_000 => 3, - 12_000_000...18_000_000 => 2, - 6_000_000...12_000_000 => 1, + 24_000_000..=48_000_000 => 4, + 18_000_000..=24_000_000 => 3, + 12_000_000..=18_000_000 => 2, + 6_000_000..=12_000_000 => 1, _ => unreachable!(), }; @@ -226,9 +226,9 @@ impl CoreClk { // Calculate PLL Q ratio let q = match pllout_freq { - 192_000_000...384_000_000 => 2, - 96_000_000...192_000_000 => 4, - 48_000_000...96_000_000 => 8, + 192_000_000..=384_000_000 => 2, + 96_000_000..=192_000_000 => 4, + 48_000_000..=96_000_000 => 8, _ => unreachable!(), }; From 9a8cea2ec60257f8ff3c352c6ef9985a35bb29c7 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:39:15 +0300 Subject: [PATCH 099/315] Bump version (0.5.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eac973f..cf80ffe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.4.0" +version = "0.5.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From fa8b94ab5660424ae0e09f692a075806233bf174 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:47:53 +0300 Subject: [PATCH 100/315] Update e310x-hal dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3f43257..88ec87c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["riscv", "register", "peripheral"] license = "ISC" [dependencies] -e310x-hal = "0.4.0" +e310x-hal = "0.5.0" [features] board-hifive1 = [] From 0635193887f441c2902bbd7232fe9fdd02cb81c7 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 15:55:49 +0300 Subject: [PATCH 101/315] Downgrade memory definitions to prevent bootloader destruction --- memory-hifive1-revb.x | 12 +----------- memory-hifive1.x | 12 +----------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/memory-hifive1-revb.x b/memory-hifive1-revb.x index e9e4bc5..516306c 100644 --- a/memory-hifive1-revb.x +++ b/memory-hifive1-revb.x @@ -1,15 +1,5 @@ INCLUDE memory-fe310.x MEMORY { - FLASH : ORIGIN = 0x20000000, LENGTH = 4M + FLASH : ORIGIN = 0x20010000, LENGTH = 4032K } - -REGION_ALIAS("REGION_TEXT", FLASH); -REGION_ALIAS("REGION_RODATA", FLASH); -REGION_ALIAS("REGION_DATA", RAM); -REGION_ALIAS("REGION_BSS", RAM); -REGION_ALIAS("REGION_HEAP", RAM); -REGION_ALIAS("REGION_STACK", RAM); - -/* Skip first 64k allocated for bootloader */ -_stext = 0x20010000; diff --git a/memory-hifive1.x b/memory-hifive1.x index cd55c70..f38703b 100644 --- a/memory-hifive1.x +++ b/memory-hifive1.x @@ -1,15 +1,5 @@ INCLUDE memory-fe310.x MEMORY { - FLASH : ORIGIN = 0x20000000, LENGTH = 16M + FLASH : ORIGIN = 0x20400000, LENGTH = 12M } - -REGION_ALIAS("REGION_TEXT", FLASH); -REGION_ALIAS("REGION_RODATA", FLASH); -REGION_ALIAS("REGION_DATA", RAM); -REGION_ALIAS("REGION_BSS", RAM); -REGION_ALIAS("REGION_HEAP", RAM); -REGION_ALIAS("REGION_STACK", RAM); - -/* Skip first 4M allocated for bootloader */ -_stext = 0x20400000; From 747b66a6537bff70b58e4d50b2e1a42cc70ed865 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 16:15:04 +0300 Subject: [PATCH 102/315] Use digital::v2 traits --- Cargo.toml | 1 + src/led.rs | 14 +++++++------- src/lib.rs | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 88ec87c..dbeea96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ license = "ISC" [dependencies] e310x-hal = "0.5.0" +embedded-hal = "0.2.3" [features] board-hifive1 = [] diff --git a/src/led.rs b/src/led.rs index 1f321e1..521c050 100644 --- a/src/led.rs +++ b/src/led.rs @@ -3,7 +3,7 @@ //! - Red = Pin 22 //! - Green = Pin 19 //! - Blue = Pin 21 -use hal::prelude::*; +use embedded_hal::digital::v2::OutputPin; use hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, OUT_XOR, IOF_EN}; use hal::gpio::{Output, Regular, Invert}; @@ -56,30 +56,30 @@ pub trait Led { impl Led for RED { fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); + self.set_low().unwrap(); } fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); + self.set_high().unwrap(); } } impl Led for GREEN { fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); + self.set_low().unwrap(); } fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); + self.set_high().unwrap(); } } impl Led for BLUE { fn off(&mut self) { - _embedded_hal_digital_OutputPin::set_low(self); + self.set_low().unwrap(); } fn on(&mut self) { - _embedded_hal_digital_OutputPin::set_high(self); + self.set_high().unwrap(); } } diff --git a/src/lib.rs b/src/lib.rs index 2fc6ca4..71fc5b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![no_std] pub extern crate e310x_hal as hal; +extern crate embedded_hal; pub mod clock; #[cfg(feature = "board-hifive1")] From e692dd936ab602c2416990a0487b527fa94730ee Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 16:17:37 +0300 Subject: [PATCH 103/315] Add support for HiFive1 Rev B --- Cargo.toml | 3 ++- ci/script.sh | 1 + src/clock.rs | 7 ++++--- src/lib.rs | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbeea96..210d48a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,8 @@ embedded-hal = "0.2.3" [features] board-hifive1 = [] +board-hifive1-revb = ["e310x-hal/g002"] board-lofive = [] [package.metadata.docs.rs] -features = ['board-hifive1'] +features = ['board-hifive1-revb'] diff --git a/ci/script.sh b/ci/script.sh index 31f4802..a0c30a3 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -4,4 +4,5 @@ set -euxo pipefail cargo check --target $TARGET cargo check --target $TARGET --features 'board-hifive1' +cargo check --target $TARGET --features 'board-hifive1-revb' cargo check --target $TARGET --features 'board-lofive' diff --git a/src/clock.rs b/src/clock.rs index 027f397..5af13ea 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,16 +1,17 @@ //! Board-specific clock configuration -#[cfg(any(feature = "board-hifive1", feature = "board-lofive"))] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-lofive"))] use hal::{ e310x::{PRCI, AONCLK}, clock::{Clocks, PrciExt, AonExt}, time::Hertz, }; -#[cfg(feature = "board-hifive1")] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Configures clock generation system. /// -/// For HiFive1 board external oscillators are enabled for both high-frequency and low-frequency clocks. +/// For HiFive1 and HiFive1 Rev B boards external oscillators are enabled for +/// both high-frequency and low-frequency clocks. pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); diff --git a/src/lib.rs b/src/lib.rs index 71fc5b2..45e7d37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,10 @@ pub extern crate e310x_hal as hal; extern crate embedded_hal; pub mod clock; -#[cfg(feature = "board-hifive1")] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub mod led; pub mod serial; -#[cfg(feature = "board-hifive1")] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub use led::{RED, GREEN, BLUE, rgb, Led}; pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; From 380538e63b6eb55abaf588117159ddeab8f7a3c8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 16:31:58 +0300 Subject: [PATCH 104/315] Enforce board selection, provide old-style memory.x --- build.rs | 38 ++++++++++++++++++++++++++++++-------- ci/script.sh | 1 - src/clock.rs | 1 - 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/build.rs b/build.rs index 45b0eae..e8fd4a3 100644 --- a/build.rs +++ b/build.rs @@ -1,17 +1,39 @@ use std::{env, fs}; use std::path::PathBuf; -use std::io::Write; fn main() { - // Put the linker script somewhere the linker can find it + // Put the memory definitions somewhere the linker can find it let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out_dir.display()); - fs::File::create(out_dir.join("memory-hifive1.x")).unwrap() - .write_all(include_bytes!("memory-hifive1.x")).unwrap(); - println!("cargo:rerun-if-changed=memory-hifive1.x"); + let boards: Vec<_> = env::vars().filter_map(|(key, _value)| { + if key.starts_with("CARGO_FEATURE_BOARD") { + Some(key[20..].to_ascii_lowercase()) // Strip 'CARGO_FEATURE_BOARD_' + } else { + None + } + }).collect(); - fs::File::create(out_dir.join("memory-hifive1-revb.x")).unwrap() - .write_all(include_bytes!("memory-hifive1-revb.x")).unwrap(); - println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); + if boards.is_empty() { + panic!("No board features selected"); + } + if boards.len() > 1 { + panic!("More than one board feature selected: {:?}", boards); + } + + let board = boards.first().unwrap(); + + match board.as_str() { + "hifive1" => { + fs::copy("memory-hifive1.x", out_dir.join("memory.x")).unwrap(); + println!("cargo:rerun-if-changed=memory-hifive1.x"); + } + "hifive1_revb" => { + fs::copy("memory-hifive1-revb.x", out_dir.join("memory.x")).unwrap(); + println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); + } + "lofive" => {} + + other => panic!("Unknown board: {}", other), + } } diff --git a/ci/script.sh b/ci/script.sh index a0c30a3..29cd4d2 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -2,7 +2,6 @@ set -euxo pipefail -cargo check --target $TARGET cargo check --target $TARGET --features 'board-hifive1' cargo check --target $TARGET --features 'board-hifive1-revb' cargo check --target $TARGET --features 'board-lofive' diff --git a/src/clock.rs b/src/clock.rs index 5af13ea..bbfed6a 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,6 +1,5 @@ //! Board-specific clock configuration -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-lofive"))] use hal::{ e310x::{PRCI, AONCLK}, clock::{Clocks, PrciExt, AonExt}, From 96dd9c1e0a620711c35d253d5508a4f991210d49 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Thu, 6 Jun 2019 16:37:47 +0300 Subject: [PATCH 105/315] Bump version (0.5.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 210d48a..0ad53ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.4.0" +version = "0.5.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From b1fa95d691bd0942e46f136c1fc04b9ff42646f3 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 7 Jun 2019 21:28:36 +0300 Subject: [PATCH 106/315] Update prelude --- src/prelude.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/prelude.rs b/src/prelude.rs index 0b2ce54..c75c57a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,11 +1,18 @@ //! Prelude pub use embedded_hal::prelude::*; +pub use embedded_hal::digital::v2::{ + InputPin as _embedded_hal_digital_v2_InputPin, + OutputPin as _embedded_hal_digital_v2_OutputPin, + StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, + ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, +}; pub use crate::clint::ClintExt as _e310x_hal_clint_ClintExt; pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; pub use crate::plic::PlicExt as _e310x_hal_plic_PlicExt; pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; +pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; From 287bf43443e85acfd8ef6819a78074d622565c35 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 8 Jun 2019 21:35:50 +0300 Subject: [PATCH 107/315] I2C driver (WIP) --- src/i2c.rs | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 + 2 files changed, 290 insertions(+) create mode 100644 src/i2c.rs diff --git a/src/i2c.rs b/src/i2c.rs new file mode 100644 index 0000000..a1db304 --- /dev/null +++ b/src/i2c.rs @@ -0,0 +1,287 @@ +//! I2C Master Interface +//! +//! The SiFive Inter-Integrated Circuit (I2C) Master Interface +//! is based on OpenCores® I2C Master Core. + +use e310x::{I2C0, i2c0}; +use core::ops::Deref; +use core::mem; +use crate::gpio::{gpio0, IOF0}; +use crate::time::Bps; +use crate::clock::Clocks; +use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; + +/// SDA pin - DO NOT IMPLEMENT THIS TRAIT +pub unsafe trait SdaPin {} +/// SCL pin - DO NOT IMPLEMENT THIS TRAIT +pub unsafe trait SclPin {} + +unsafe impl SdaPin for gpio0::Pin12> { } +unsafe impl SclPin for gpio0::Pin13> { } + +/// I2C error +#[derive(Debug, Eq, PartialEq)] +pub enum Error { + /// Invalid peripheral state + InvalidState, + + /// Arbitration lost + ArbitrationLost, + + /// No ACK received + NoAck, +} + +/// Transmission speed +pub enum Speed { + /// 100Kbps + Normal, + + /// 400Kbps + Fast, + + /// Custom speed + Custom(Bps), +} + + +/// I2C abstraction +pub struct I2c { + i2c: I2C, + pins: PINS, +} + +impl I2c { + /// Configures an I2C peripheral + pub fn new(i2c: I2C0, sda: SDA, scl: SCL, speed: Speed, clocks: Clocks) -> Self + where SDA: SdaPin, SCL: SclPin { + // Calculate prescaler value + let desired_speed = match speed { + Speed::Normal => 100_000, + Speed::Fast => 400_000, + Speed::Custom(bps) => bps.0, + }; + let clock = clocks.tlclk().0; + assert!(desired_speed * 5 <= clock); + let prescaler = clock / (5 * desired_speed) - 1; + assert!(prescaler < (1 << 16)); + + // Turn off i2c + i2c.ctr.write(|w| w.en().clear_bit().ien().clear_bit()); + + // Set prescaler + let prescaler_lo = (prescaler & 0xff) as u8; + let prescaler_hi = ((prescaler >> 8) & 0xff) as u8; + i2c.prer_lo.write(|w| unsafe { w.value().bits(prescaler_lo) }); + i2c.prer_hi.write(|w| unsafe { w.value().bits(prescaler_hi) }); + + // Turn on i2c + i2c.ctr.write(|w| w.en().set_bit()); + + Self { + i2c, + pins: (sda, scl) + } + } +} + +impl I2c { + /// Releases the I2C peripheral and associated pins + pub fn free(self) -> (I2C, PINS) { + (self.i2c, self.pins) + } +} + +impl, PINS> I2c { + fn write_cr(&self, f: F) + where F: FnOnce(&mut i2c0::cr::W) -> &mut i2c0::cr::W + { + self.i2c.cr_sr.write(|w| unsafe { + let mut value: u32 = 0; + f(mem::transmute(&mut value)); + w.bits(value) + }); + } + + fn read_sr(&self) -> i2c0::sr::R { + unsafe { + mem::transmute(self.i2c.cr_sr.read()) + } + } + + fn write_byte(&self, byte: u8) { + self.i2c.txr_rxr.write(|w| unsafe { + w.data().bits(byte) + }); + } + + fn read_byte(&self) -> u8 { + self.i2c.txr_rxr.read().data().bits() + } + + fn wait_for_interrupt(&self) -> Result<(), Error> { + loop { + let sr = self.read_sr(); + + if sr.al().bit_is_set() { + // Set STOP + self.write_cr(|w| w.sto().set_bit()); + self.wait_for_complete(); + + return Err(Error::ArbitrationLost); + } + + if sr.if_().bit_is_set() { + // ACK the interrupt + self.write_cr(|w| w.iack().set_bit()); + + return Ok(()); + } + } + } + + fn wait_for_read(&self) -> Result<(), Error> { + self.wait_for_interrupt() + } + + fn wait_for_write(&self) -> Result<(), Error> { + self.wait_for_interrupt()?; + + if self.read_sr().rx_ack().bit_is_set() { + // Set STOP + self.write_cr(|w| w.sto().set_bit()); + self.wait_for_complete(); + + return Err(Error::NoAck); + } + + Ok(()) + } + + fn wait_for_complete(&self) { + while self.read_sr().busy().bit_is_set() { } + } +} + +const FLAG_READ: u8 = 1; +const FLAG_WRITE: u8 = 0; + +impl, PINS> Read for I2c { + type Error = Error; + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + if self.read_sr().busy().bit_is_set() { + return Err(Error::InvalidState); + } + + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Read bytes + let buffer_len = buffer.len(); + for (i, byte) in buffer.iter_mut().enumerate() { + if i != buffer_len - 1 { + // R + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // R + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + Ok(()) + } +} + +impl, PINS> Write for I2c { + type Error = Error; + + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + if self.read_sr().busy().bit_is_set() { + return Err(Error::InvalidState); + } + + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + for (i, byte) in bytes.iter().enumerate() { + self.write_byte(*byte); + + if i != bytes.len() - 1 { + self.write_cr(|w| w.wr().set_bit()); + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); + } + self.wait_for_write()?; + } + Ok(()) + } +} + +impl, PINS> WriteRead for I2c { + type Error = Error; + + fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + if self.read_sr().busy().bit_is_set() { + return Err(Error::InvalidState); + } + + if !bytes.is_empty() && buffer.is_empty() { + self.write(address, bytes) + } else if !buffer.is_empty() && bytes.is_empty() { + self.read(address, buffer) + } else if bytes.is_empty() && buffer.is_empty() { + Ok(()) + } else { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + for byte in bytes { + self.write_byte(*byte); + + self.write_cr(|w| w.wr().set_bit()); + self.wait_for_write()?; + } + + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Read bytes + let buffer_len = buffer.len(); + for (i, byte) in buffer.iter_mut().enumerate() { + if i != buffer_len - 1 { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + + Ok(()) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 40751fb..62aebff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,3 +19,6 @@ pub mod spi; pub mod stdout; pub mod time; pub mod wdog; + +#[cfg(feature = "g002")] +pub mod i2c; From 6f48801b060ea9d7d41f7ea95f0295fcf87bd92f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 01:25:06 +0300 Subject: [PATCH 108/315] Reset i2c state before each block transfer --- src/i2c.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/i2c.rs b/src/i2c.rs index a1db304..7d5202a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -93,6 +93,11 @@ impl I2c { } impl, PINS> I2c { + fn reset(&self) { + // ACK pending interrupt event, clear commands + self.write_cr(|w| w.iack().set_bit()); + } + fn write_cr(&self, f: F) where F: FnOnce(&mut i2c0::cr::W) -> &mut i2c0::cr::W { @@ -170,6 +175,8 @@ impl, PINS> Read for I2c { type Error = Error; fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.reset(); + if self.read_sr().busy().bit_is_set() { return Err(Error::InvalidState); } @@ -203,6 +210,8 @@ impl, PINS> Write for I2c { type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.reset(); + if self.read_sr().busy().bit_is_set() { return Err(Error::InvalidState); } @@ -233,6 +242,8 @@ impl, PINS> WriteRead for I2c type Error = Error; fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + self.reset(); + if self.read_sr().busy().bit_is_set() { return Err(Error::InvalidState); } From 7f0d11ac9eb250edb60b5d1a6856ac7f53cdcc6c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 01:48:53 +0300 Subject: [PATCH 109/315] Add mtime-based Delay --- src/delay.rs | 36 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 37 insertions(+) create mode 100644 src/delay.rs diff --git a/src/delay.rs b/src/delay.rs new file mode 100644 index 0000000..f7b18c2 --- /dev/null +++ b/src/delay.rs @@ -0,0 +1,36 @@ +//! # Delays + +use embedded_hal::blocking::delay::DelayMs; +use crate::clint::MTIME; + +/// Machine timer (mtime) as a delay provider +pub struct Delay; + +impl Delay { + /// Constructs a delay provider based on the machine timer (mtime) + pub fn new() -> Self { + Delay + } +} + +impl DelayMs for Delay { + fn delay_ms(&mut self, ms: u32) { + let ticks = (ms as u64) * 65536 / 1000; + + let mtime = MTIME; + let t = mtime.mtime() + ticks; + while mtime.mtime() < t { } + } +} + +impl DelayMs for Delay { + fn delay_ms(&mut self, ms: u16) { + self.delay_ms(u32::from(ms)); + } +} + +impl DelayMs for Delay { + fn delay_ms(&mut self, ms: u8) { + self.delay_ms(u32::from(ms)); + } +} diff --git a/src/lib.rs b/src/lib.rs index 62aebff..4440b94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub use e310x; pub mod clint; pub mod clock; +pub mod delay; pub mod gpio; pub mod plic; pub mod prelude; From 5ae1c40c7c0fda120a3b7e0ff7a8dc02f9670864 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 02:03:03 +0300 Subject: [PATCH 110/315] Implement UART1 serial driver for G002 chips --- src/serial.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index 897cefc..0e5e057 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -19,7 +19,8 @@ use core::convert::Infallible; use embedded_hal::serial; use nb; -use e310x::UART0; +#[allow(unused_imports)] +use e310x::{UART0, UART1}; use crate::clock::Clocks; use crate::gpio::{IOF0, gpio0}; use crate::time::Bps; @@ -34,6 +35,13 @@ pub unsafe trait RxPin {} unsafe impl TxPin for gpio0::Pin17> {} unsafe impl RxPin for gpio0::Pin16> {} +#[cfg(feature = "g002")] +mod g002_ims { + use super::{TxPin, RxPin, UART1, gpio0, IOF0}; + unsafe impl TxPin for gpio0::Pin18> {} + unsafe impl RxPin for gpio0::Pin23> {} +} + /// Serial abstraction pub struct Serial { uart: UART, @@ -160,3 +168,8 @@ macro_rules! hal { hal! { UART0: uart0 } + +#[cfg(feature = "g002")] +hal! { + UART1: uart1 +} From 6c1033009c304d1877f441f097e8bef703a29055 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 02:27:13 +0300 Subject: [PATCH 111/315] Get rid of macro generation in serial driver --- src/serial.rs | 230 ++++++++++++++++++++++++++------------------------ 1 file changed, 119 insertions(+), 111 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 0e5e057..937868a 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -9,21 +9,22 @@ //! //! # UART1 //! *Warning:* UART1 pins are not connected to package in FE310-G000 -//! - TX: Pin 25 IOF0 -//! - RX: Pin 24 IOF0 +//! - TX: Pin 18 IOF0 +//! - RX: Pin 23 IOF0 //! - Interrupt::UART1 -use core::marker::PhantomData; use core::convert::Infallible; +use core::ops::Deref; use embedded_hal::serial; use nb; -#[allow(unused_imports)] -use e310x::{UART0, UART1}; use crate::clock::Clocks; -use crate::gpio::{IOF0, gpio0}; +use crate::gpio::{gpio0, IOF0}; use crate::time::Bps; +#[allow(unused_imports)] +use e310x::{uart0, UART0, UART1}; +use core::mem; // FIXME these should be "closed" traits /// TX pin - DO NOT IMPLEMENT THIS TRAIT @@ -37,11 +38,16 @@ unsafe impl RxPin for gpio0::Pin16> {} #[cfg(feature = "g002")] mod g002_ims { - use super::{TxPin, RxPin, UART1, gpio0, IOF0}; + use super::{gpio0, RxPin, TxPin, IOF0, UART1}; unsafe impl TxPin for gpio0::Pin18> {} unsafe impl RxPin for gpio0::Pin23> {} } +#[doc(hidden)] +pub trait UartX: Deref {} +impl UartX for UART0 {} +impl UartX for UART1 {} + /// Serial abstraction pub struct Serial { uart: UART, @@ -50,126 +56,128 @@ pub struct Serial { /// Serial receiver pub struct Rx { - _uart: PhantomData, + uart: UART, } /// Serial transmitter pub struct Tx { - _uart: PhantomData, + uart: UART, } -macro_rules! hal { - ($( - $UARTX:ident: $uartX:ident - )+) => { - $( - impl Serial<$UARTX, (TX, RX)> { - /// Configures a UART peripheral to provide serial communication - pub fn $uartX( - uart: $UARTX, - pins: (TX, RX), - baud_rate: Bps, - clocks: Clocks, - ) -> Self - where - TX: TxPin<$UARTX>, - RX: RxPin<$UARTX>, - { - let div = clocks.tlclk().0 / baud_rate.0 - 1; - unsafe { uart.div.write(|w| w.bits(div)); } - - uart.txctrl.write(|w| w.enable().bit(true)); - uart.rxctrl.write(|w| w.enable().bit(true)); - - Serial { uart, pins } - } - - /// Starts listening for an interrupt event - pub fn listen(self) -> Self { - self.uart.ie.write(|w| w.txwm().bit(false) - .rxwm().bit(true)); - self - } - - /// Stops listening for an interrupt event - pub fn unlisten(self) -> Self { - self.uart.ie.write(|w| w.txwm().bit(false) - .rxwm().bit(false)); - self - } - - /// Splits the `Serial` abstraction into a transmitter and a - /// receiver half - pub fn split(self) -> (Tx<$UARTX>, Rx<$UARTX>) { - ( - Tx { - _uart: PhantomData, - }, - Rx { - _uart: PhantomData, - }, - ) - } - - /// Releases the UART peripheral and associated pins - pub fn free(self) -> ($UARTX, (TX, RX)) { - (self.uart, self.pins) - } - } +impl Serial { + /// Configures a UART peripheral to provide serial communication + pub fn new(uart: UART, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self + where + TX: TxPin, + RX: RxPin, + { + let div = clocks.tlclk().0 / baud_rate.0 - 1; + unsafe { + uart.div.write(|w| w.bits(div)); + } + + uart.txctrl.write(|w| w.enable().bit(true)); + uart.rxctrl.write(|w| w.enable().bit(true)); + + Serial { uart, pins } + } - impl serial::Read for Rx<$UARTX> { - type Error = Infallible; + /// Starts listening for an interrupt event + pub fn listen(self) -> Self { + self.uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(true)); + self + } - fn read(&mut self) -> nb::Result { - // NOTE(unsafe) atomic read with no side effects - let rxdata = unsafe { (*$UARTX::ptr()).rxdata.read() }; + /// Stops listening for an interrupt event + pub fn unlisten(self) -> Self { + self.uart + .ie + .write(|w| w.txwm().bit(false).rxwm().bit(false)); + self + } - if rxdata.empty().bit_is_set() { - Err(::nb::Error::WouldBlock) - } else { - Ok(rxdata.data().bits() as u8) - } - } + /// Splits the `Serial` abstraction into a transmitter and a + /// receiver half + pub fn split(self) -> (Tx, Rx) { + ( + Tx { + uart: unsafe { mem::zeroed() } + }, + Rx { + uart: self.uart } + ) + } + + /// Releases the UART peripheral and associated pins + pub fn free(self) -> (UART, (TX, RX)) { + (self.uart, self.pins) + } +} - impl serial::Write for Tx<$UARTX> { - type Error = Infallible; - - fn flush(&mut self) -> nb::Result<(), Infallible> { - // NOTE(unsafe) atomic read with no side effects - let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; - - if txdata.full().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - Ok(()) - } - } - - fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { - // NOTE(unsafe) atomic read with no side effects - let txdata = unsafe { (*$UARTX::ptr()).txdata.read() }; - - if txdata.full().bit_is_set() { - Err(::nb::Error::WouldBlock) - } else { - unsafe { - (*$UARTX::ptr()).txdata - .write(|w| w.data().bits(byte)); - } - Ok(()) - } - } +impl serial::Read for Rx { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + let rxdata = self.uart.rxdata.read(); + + if rxdata.empty().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits() as u8) + } + } +} + +impl serial::Write for Tx { + type Error = Infallible; + + fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { + let txdata = self.uart.txdata.read(); + + if txdata.full().bit_is_set() { + Err(::nb::Error::WouldBlock) + } else { + unsafe { + self.uart.txdata.write(|w| w.data().bits(byte)); } - )+ + Ok(()) + } + } + + fn flush(&mut self) -> nb::Result<(), Infallible> { + let txdata = self.uart.txdata.read(); + + if txdata.full().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } } } -hal! { - UART0: uart0 +// Backward compatibility +impl Serial { + /// Configures a UART peripheral to provide serial communication + #[deprecated(note = "Please use Serial::new function instead")] + pub fn uart0(uart: UART0, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self + where + TX: TxPin, + RX: RxPin, + { + Self::new(uart, pins, baud_rate, clocks) + } } #[cfg(feature = "g002")] -hal! { - UART1: uart1 +impl Serial { + /// Configures a UART peripheral to provide serial communication + #[deprecated(note = "Please use Serial::new function instead")] + pub fn uart1(uart: UART1, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self + where + TX: TxPin, + RX: RxPin, + { + Self::new(uart, pins, baud_rate, clocks) + } } From 4d5a53e78d249489e81c8518c976bc058a3a8e1f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 02:33:12 +0300 Subject: [PATCH 112/315] Bump version (0.5.1) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cf80ffe..324ed45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.5.0" +version = "0.5.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 9f6d58ae726eb515df84b4bbfe8faedb805951d0 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 12:57:41 +0300 Subject: [PATCH 113/315] Get rid of macro generation in SPI driver --- src/spi.rs | 297 +++++++++++++++++++++++++++++------------------------ 1 file changed, 162 insertions(+), 135 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index f53803e..b34b671 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -24,8 +24,9 @@ //! - Interrupt::QSPI0 use core::convert::Infallible; +use core::ops::Deref; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -use crate::e310x::{QSPI0, QSPI1, QSPI2}; +use crate::e310x::{QSPI0, QSPI1, QSPI2, qspi0}; use crate::gpio::{IOF0, gpio0}; use crate::clock::Clocks; use crate::time::Hertz; @@ -75,147 +76,173 @@ impl Pins for (gpio0::Pin27>, gpio0::Pin28>, gpio0::Pi const CS_INDEX: Option = Some(0); } + +#[doc(hidden)] +pub trait SpiX: Deref {} +impl SpiX for QSPI0 {} +impl SpiX for QSPI1 {} +impl SpiX for QSPI2 {} + + /// SPI abstraction pub struct Spi { spi: SPI, pins: PINS, } -macro_rules! hal { - ($($SPIX:ident: $spiX:ident,)+) => { - $( - impl Spi<$SPIX, PINS> { - /// Configures the SPI peripheral to operate in full duplex master mode - pub fn $spiX( - spi: $SPIX, - pins: PINS, - mode: Mode, - freq: Hertz, - clocks: Clocks, - ) -> Self - where - PINS: Pins<$SPIX>, - { - let div = clocks.tlclk().0 / (2 * freq.0) - 1; - spi.div.write(|w| unsafe { w.bits(div) }); - - let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { - spi.csid.write(|w| unsafe { w.bits(cs_index) }); - - 0 // AUTO: Assert/de-assert CS at the beginning/end of each frame - } else { - 3 // OFF: Disable hardware control of the CS pin - }; - spi.csmode.write(|w| unsafe { w.bits(cs_mode) }); - - // Set CS pin polarity to high - spi.csdef.reset(); - - // Set SPI mode - let phase = mode.phase == Phase::CaptureOnSecondTransition; - let polarity = mode.polarity == Polarity::IdleHigh; - spi.mode.write(|w| w - .phase().bit(phase) - .polarity().bit(polarity) - ); - - spi.fmt.write(|w| unsafe { w - .protocol().bits(0) // Single - .endian().clear_bit() // Transmit most-significant bit (MSB) first - .direction().rx() - .length().bits(8) - }); - - // Set watermark levels - spi.txmark.write(|w| unsafe { w.value().bits(1) }); - spi.rxmark.write(|w| unsafe { w.value().bits(0) }); - - spi.delay0.reset(); - spi.delay1.reset(); - - Self { spi, pins } - } - - /// Sets transmit watermark level - pub fn set_tx_watermark(&mut self, value: u8) { - self.spi.txmark.write(|w| unsafe { w.value().bits(value) }); - } - - /// Sets receive watermark level - pub fn set_rx_watermark(&mut self, value: u8) { - self.spi.rxmark.write(|w| unsafe { w.value().bits(value) }); - } - - /// Returns transmit watermark event status - pub fn tx_wm_is_pending(&self) -> bool { - self.spi.ip.read().txwm().bit() - } - - /// Returns receive watermark event status - pub fn rx_wm_is_pending(&self) -> bool { - self.spi.ip.read().rxwm().bit() - } - - /// Starts listening for transmit watermark interrupt event - pub fn listen_tx_wm(&mut self) { - self.spi.ie.write(|w| w.txwm().set_bit()) - } - - /// Starts listening for receive watermark interrupt event - pub fn listen_rx_wm(&mut self) { - self.spi.ie.write(|w| w.rxwm().set_bit()) - } - - /// Stops listening for transmit watermark interrupt event - pub fn unlisten_tx_wm(&mut self) { - self.spi.ie.write(|w| w.txwm().clear_bit()) - } - - /// Stops listening for receive watermark interrupt event - pub fn unlisten_rx_wm(&mut self) { - self.spi.ie.write(|w| w.rxwm().clear_bit()) - } - - /// Releases the SPI peripheral and associated pins - pub fn free(self) -> ($SPIX, PINS) { - (self.spi, self.pins) - } - } - - impl embedded_hal::spi::FullDuplex for Spi<$SPIX, PINS> { - type Error = Infallible; - - fn read(&mut self) -> nb::Result { - let rxdata = self.spi.rxdata.read(); - - if rxdata.empty().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - Ok(rxdata.data().bits()) - } - } - - fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - let txdata = self.spi.txdata.read(); - - if txdata.full().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); - Ok(()) - } - } - } - - impl embedded_hal::blocking::spi::transfer::Default for Spi<$SPIX, PINS> {} - - impl embedded_hal::blocking::spi::write::Default for Spi<$SPIX, PINS> {} - )+ +impl Spi { + /// Configures the SPI peripheral to operate in full duplex master mode + pub fn new(spi: SPI, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self + where + PINS: Pins + { + let div = clocks.tlclk().0 / (2 * freq.0) - 1; + spi.div.write(|w| unsafe { w.bits(div) }); + + let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { + spi.csid.write(|w| unsafe { w.bits(cs_index) }); + + 0 // AUTO: Assert/de-assert CS at the beginning/end of each frame + } else { + 3 // OFF: Disable hardware control of the CS pin + }; + spi.csmode.write(|w| unsafe { w.bits(cs_mode) }); + + // Set CS pin polarity to high + spi.csdef.reset(); + + // Set SPI mode + let phase = mode.phase == Phase::CaptureOnSecondTransition; + let polarity = mode.polarity == Polarity::IdleHigh; + spi.mode.write(|w| w + .phase().bit(phase) + .polarity().bit(polarity) + ); + + spi.fmt.write(|w| unsafe { w + .protocol().bits(0) // Single + .endian().clear_bit() // Transmit most-significant bit (MSB) first + .direction().rx() + .length().bits(8) + }); + + // Set watermark levels + spi.txmark.write(|w| unsafe { w.value().bits(1) }); + spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + + spi.delay0.reset(); + spi.delay1.reset(); + + Self { spi, pins } + } + + /// Sets transmit watermark level + pub fn set_tx_watermark(&mut self, value: u8) { + self.spi.txmark.write(|w| unsafe { w.value().bits(value) }); + } + + /// Sets receive watermark level + pub fn set_rx_watermark(&mut self, value: u8) { + self.spi.rxmark.write(|w| unsafe { w.value().bits(value) }); + } + + /// Returns transmit watermark event status + pub fn tx_wm_is_pending(&self) -> bool { + self.spi.ip.read().txwm().bit() + } + + /// Returns receive watermark event status + pub fn rx_wm_is_pending(&self) -> bool { + self.spi.ip.read().rxwm().bit() + } + + /// Starts listening for transmit watermark interrupt event + pub fn listen_tx_wm(&mut self) { + self.spi.ie.write(|w| w.txwm().set_bit()) + } + + /// Starts listening for receive watermark interrupt event + pub fn listen_rx_wm(&mut self) { + self.spi.ie.write(|w| w.rxwm().set_bit()) + } + + /// Stops listening for transmit watermark interrupt event + pub fn unlisten_tx_wm(&mut self) { + self.spi.ie.write(|w| w.txwm().clear_bit()) + } + + /// Stops listening for receive watermark interrupt event + pub fn unlisten_rx_wm(&mut self) { + self.spi.ie.write(|w| w.rxwm().clear_bit()) + } + + /// Releases the SPI peripheral and associated pins + pub fn free(self) -> (SPI, PINS) { + (self.spi, self.pins) + } +} + +impl embedded_hal::spi::FullDuplex for Spi { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + let rxdata = self.spi.rxdata.read(); + + if rxdata.empty().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits()) + } + } + + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + let txdata = self.spi.txdata.read(); + + if txdata.full().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + Ok(()) + } + } +} + +impl embedded_hal::blocking::spi::transfer::Default for Spi {} + +impl embedded_hal::blocking::spi::write::Default for Spi {} + + + +// Backward compatibility +impl Spi { + /// Configures the SPI peripheral to operate in full duplex master mode + #[deprecated(note = "Please use Spi::new function instead")] + pub fn spi0(spi: QSPI0, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self + where + PINS: Pins + { + Self::new(spi, pins, mode, freq, clocks) + } +} + +impl Spi { + /// Configures the SPI peripheral to operate in full duplex master mode + #[deprecated(note = "Please use Spi::new function instead")] + pub fn spi1(spi: QSPI1, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self + where + PINS: Pins + { + Self::new(spi, pins, mode, freq, clocks) } } -hal! { - QSPI0: spi0, - QSPI1: spi1, - QSPI2: spi2, +impl Spi { + /// Configures the SPI peripheral to operate in full duplex master mode + #[deprecated(note = "Please use Spi::new function instead")] + pub fn spi2(spi: QSPI2, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self + where + PINS: Pins + { + Self::new(spi, pins, mode, freq, clocks) + } } From 363a144b6f9bcbd2e91ef13c0ed0a5035cb672d9 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 14:38:39 +0300 Subject: [PATCH 114/315] GPIO refactoring: hide auxiliary registers, use atomics to access them --- src/gpio.rs | 442 +++++++++++++++++++++------------------------------- 1 file changed, 175 insertions(+), 267 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index b3364fa..8d2345c 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,6 +1,7 @@ //! General Purpose I/O use core::marker::PhantomData; +use core::sync::atomic::{AtomicU32, Ordering}; /// GpioExt trait extends the GPIO0 peripheral. pub trait GpioExt { @@ -54,9 +55,87 @@ pub struct NoInvert; pub struct Invert; +trait PinIndex { + const INDEX: usize; +} + +#[inline(always)] +fn atomic_set_bit(r: &AtomicU32, index: usize, bit: bool) { + let mask = 1 << (index & 31); + match bit { + true => r.fetch_or(mask, Ordering::SeqCst), + false => r.fetch_and(!mask, Ordering::SeqCst), + }; +} + +trait PeripheralAccess { + fn peripheral() -> &'static e310x::gpio0::RegisterBlock; + + fn value(index: usize) -> bool { + let p = Self::peripheral(); + (p.value.read().bits() >> (index & 31)) != 0 + } + + fn set_input_en(index: usize, bit: bool) { + let p = Self::peripheral(); + 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) }; + atomic_set_bit(r, index, bit); + } + + fn set_port(index: usize, bit: bool) { + let p = Self::peripheral(); + let r: &AtomicU32 = unsafe { core::mem::transmute(&p.port) }; + atomic_set_bit(r, index, bit); + } + + fn toggle_port(index: usize) { + let p = Self::peripheral(); + let r: &AtomicU32 = unsafe { core::mem::transmute(&p.port) }; + 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) }; + 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) }; + 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) }; + 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) }; + 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) }; + atomic_set_bit(r, index, bit); + } +} + + macro_rules! gpio { - ($GPIOX:ident, $gpiox:ident, $gpioy:ident, [ - $($PXi:ident: ($pxi:ident, $MODE:ty),)+ + ($GPIOX:ident, $gpiox:ident, [ + $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+ ]) => { /// GPIO pub mod $gpiox { @@ -65,44 +144,29 @@ macro_rules! gpio { use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; - use e310x::{$gpioy, $GPIOX}; + use e310x::$GPIOX; use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, - NoInvert, Output, PullUp, Regular}; + NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess}; /// GPIO parts for fine grained permission control. pub struct Parts { - /// Opaque INPUT_EN register - pub input_en: INPUT_EN, - /// Opaque OUTPUT_EN register - pub output_en: OUTPUT_EN, - /// Opaque PULLUP register - pub pullup: PULLUP, - /// Opaque DRIVE register - pub drive: DRIVE, - /// Opaque OUT_XOR register - pub out_xor: OUT_XOR, - /// Opaque IOF_EN register - pub iof_en: IOF_EN, - /// Opaque IOF_SEL register - pub iof_sel: IOF_SEL, $( /// Pin pub $pxi: $PXi<$MODE>, )+ } + impl PeripheralAccess for $GPIOX { + fn peripheral() -> &'static e310x::gpio0::RegisterBlock { + unsafe { &*$GPIOX::ptr() } + } + } + impl GpioExt for $GPIOX { type Parts = Parts; fn split(self) -> Parts { Parts { - input_en: INPUT_EN { _0: () }, - output_en: OUTPUT_EN { _0: () }, - pullup: PULLUP { _0: () }, - drive: DRIVE { _0: () }, - out_xor: OUT_XOR { _0: () }, - iof_en: IOF_EN { _0: () }, - iof_sel: IOF_SEL { _0: () }, $( $pxi: $PXi { _mode: PhantomData }, )+ @@ -110,245 +174,102 @@ macro_rules! gpio { } } - /// Opaque INPUT_EN register - #[allow(non_camel_case_types)] - pub struct INPUT_EN { - _0: (), - } - - impl INPUT_EN { - pub(crate) fn input_en(&mut self) -> &$gpioy::INPUT_EN { - unsafe { &(*$GPIOX::ptr()).input_en } - } - } - - /// Opaque OUTPUT_EN register - #[allow(non_camel_case_types)] - pub struct OUTPUT_EN { - _0: (), - } - - impl OUTPUT_EN { - pub(crate) fn output_en(&mut self) -> &$gpioy::OUTPUT_EN { - unsafe { &(*$GPIOX::ptr()).output_en } - } - } - - /// Opaque PULLUP register - pub struct PULLUP { - _0: (), - } - - impl PULLUP { - pub(crate) fn pullup(&mut self) -> &$gpioy::PULLUP { - unsafe { &(*$GPIOX::ptr()).pullup } - } - } - - /// Opaque DRIVE register - pub struct DRIVE { - _0: (), - } - - impl DRIVE { - pub(crate) fn drive(&mut self) -> &$gpioy::DRIVE { - unsafe { &(*$GPIOX::ptr()).drive } - } - } - - - /// Opaque OUT_XOR register - #[allow(non_camel_case_types)] - pub struct OUT_XOR { - _0: (), - } - - impl OUT_XOR { - pub(crate) fn out_xor(&mut self) -> &$gpioy::OUT_XOR { - unsafe { &(*$GPIOX::ptr()).out_xor } - } - } - - /// Opaque IOF_EN register - #[allow(non_camel_case_types)] - pub struct IOF_EN { - _0: (), - } - - impl IOF_EN { - pub(crate) fn iof_en(&mut self) -> &$gpioy::IOF_EN { - unsafe { &(*$GPIOX::ptr()).iof_en } - } - } - - /// Opaque IOF_SEL register - #[allow(non_camel_case_types)] - pub struct IOF_SEL { - _0: (), - } - - impl IOF_SEL { - pub(crate) fn iof_sel(&mut self) -> &$gpioy::IOF_SEL { - unsafe { &(*$GPIOX::ptr()).iof_sel } - } - } - $( /// Pin pub struct $PXi { _mode: PhantomData, } + impl PinIndex for $PXi { + const INDEX: usize = $i; + } + impl $PXi { /// Configures the pin to serve as alternate function 0 (AF0) - pub fn into_iof0( - self, - out_xor: &mut OUT_XOR, - iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN - ) -> $PXi> { - out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); - iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(false)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); - + pub fn into_iof0(self) -> $PXi> { + $GPIOX::set_out_xor(Self::INDEX, false); + $GPIOX::set_iof_sel(Self::INDEX, false); + $GPIOX::set_iof_en(Self::INDEX, true); $PXi { _mode: PhantomData } } /// Configures the pin to serve as alternate function 1 (AF1) - pub fn into_iof1( - self, - out_xor: &mut OUT_XOR, - iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN - ) -> $PXi> { - out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); - iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); - + pub fn into_iof1(self) -> $PXi> { + $GPIOX::set_out_xor(Self::INDEX, false); + $GPIOX::set_iof_sel(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, true); $PXi { _mode: PhantomData } } /// Configures the pin to serve as inverted alternate function 0 (AF0) - pub fn into_inverted_iof0( - self, - out_xor: &mut OUT_XOR, - iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN - ) -> $PXi> { - out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); - iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(false)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); - + pub fn into_inverted_iof0(self) -> $PXi> { + $GPIOX::set_out_xor(Self::INDEX, true); + $GPIOX::set_iof_sel(Self::INDEX, false); + $GPIOX::set_iof_en(Self::INDEX, true); $PXi { _mode: PhantomData } } /// Configures the pin to serve as inverted alternate function 1 (AF1) - pub fn into_inverted_iof1( - self, - out_xor: &mut OUT_XOR, - iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN - ) -> $PXi> { - out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); - iof_sel.iof_sel().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(true)); - + pub fn into_inverted_iof1(self) -> $PXi> { + $GPIOX::set_out_xor(Self::INDEX, true); + $GPIOX::set_iof_sel(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, true); $PXi { _mode: PhantomData } } /// Configures the pin to serve as a floating input pin - pub fn into_floating_input( - self, - pullup: &mut PULLUP, - input_en: &mut INPUT_EN, - iof_en: &mut IOF_EN - ) -> $PXi> { - pullup.pullup().modify(|_, w| w.$pxi().bit(false)); - input_en.input_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_floating_input(self) -> $PXi> { + $GPIOX::set_pullup(Self::INDEX, false); + $GPIOX::set_input_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } /// Configures the pin to operate as a pulled down input pin - pub fn into_pull_up_input( - self, - pullup: &mut PULLUP, - input_en: &mut INPUT_EN, - iof_en: &mut IOF_EN - ) -> $PXi> { - pullup.pullup().modify(|_, w| w.$pxi().bit(true)); - input_en.input_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_pull_up_input(self) -> $PXi> { + $GPIOX::set_pullup(Self::INDEX, true); + $GPIOX::set_input_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } /// Configures the pin to operate as an output pin - pub fn into_output( - self, - output_en: &mut OUTPUT_EN, - drive: &mut DRIVE, - out_xor: &mut OUT_XOR, - iof_en: &mut IOF_EN - ) -> $PXi>> { - drive.drive().modify(|_, w| w.$pxi().bit(false)); - out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); - output_en.output_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_output(self) -> $PXi>> { + $GPIOX::set_drive(Self::INDEX, false); + $GPIOX::set_out_xor(Self::INDEX, false); + $GPIOX::set_output_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } /// Configures the pin to operate as an inverted output pin - pub fn into_inverted_output( - self, - output_en: &mut OUTPUT_EN, - drive: &mut DRIVE, - out_xor: &mut OUT_XOR, - iof_en: &mut IOF_EN - ) -> $PXi>> { - drive.drive().modify(|_, w| w.$pxi().bit(false)); - out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); - output_en.output_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_inverted_output(self) -> $PXi>> { + $GPIOX::set_drive(Self::INDEX, false); + $GPIOX::set_out_xor(Self::INDEX, true); + $GPIOX::set_output_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } /// Configure the pin to operate as an output pin with high /// current drive - pub fn into_output_drive( - self, - output_en: &mut OUTPUT_EN, - drive: &mut DRIVE, - out_xor: &mut OUT_XOR, - iof_en: &mut IOF_EN - ) -> $PXi>> { - drive.drive().modify(|_, w| w.$pxi().bit(true)); - out_xor.out_xor().modify(|_, w| w.$pxi().bit(false)); - output_en.output_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_output_drive(self) -> $PXi>> { + $GPIOX::set_drive(Self::INDEX, true); + $GPIOX::set_out_xor(Self::INDEX, false); + $GPIOX::set_output_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } /// Configure the pin to operate as an inverted output pin with /// high current drive - pub fn into_inverted_output_drive( - self, - output_en: &mut OUTPUT_EN, - drive: &mut DRIVE, - out_xor: &mut OUT_XOR, - iof_en: &mut IOF_EN - ) -> $PXi>> { - drive.drive().modify(|_, w| w.$pxi().bit(true)); - out_xor.out_xor().modify(|_, w| w.$pxi().bit(true)); - output_en.output_en().modify(|_, w| w.$pxi().bit(true)); - iof_en.iof_en().modify(|_, w| w.$pxi().bit(false)); - + pub fn into_inverted_output_drive(self) -> $PXi>> { + $GPIOX::set_drive(Self::INDEX, true); + $GPIOX::set_out_xor(Self::INDEX, true); + $GPIOX::set_output_en(Self::INDEX, true); + $GPIOX::set_iof_en(Self::INDEX, false); $PXi { _mode: PhantomData } } } @@ -361,9 +282,7 @@ macro_rules! gpio { } fn is_low(&self) -> Result { - let gpio = unsafe { &*$GPIOX::ptr() }; - // NOTE unsafe atomic read with no side effects - Ok(gpio.value.read().$pxi().bit()) + Ok($GPIOX::value(Self::INDEX)) } } @@ -373,9 +292,7 @@ macro_rules! gpio { } fn is_set_low(&self) -> Result { - // NOTE unsafe atomic read with no side effects - let gpio = unsafe { &*$GPIOX::ptr() }; - Ok(gpio.value.read().$pxi().bit()) + Ok($GPIOX::value(Self::INDEX)) } } @@ -383,18 +300,12 @@ macro_rules! gpio { type Error = Infallible; fn set_high(&mut self) -> Result<(), Infallible> { - // FIXME has to read register first - // use atomics - let gpio = unsafe { &*$GPIOX::ptr() }; - gpio.port.modify(|_, w| w.$pxi().bit(true)); + $GPIOX::set_port(Self::INDEX, true); Ok(()) } fn set_low(&mut self) -> Result<(), Infallible> { - // FIXME: has to read register first - // use atomics - let gpio = unsafe { &*$GPIOX::ptr() }; - gpio.port.modify(|_, w| w.$pxi().bit(false)); + $GPIOX::set_port(Self::INDEX, false); Ok(()) } } @@ -404,10 +315,7 @@ macro_rules! gpio { /// Toggles the pin state. fn toggle(&mut self) -> Result<(), Infallible> { - // FIXME: has to read register first - // use atomics - let gpio = unsafe { &*$GPIOX::ptr() }; - gpio.port.modify(|r, w| w.$pxi().bit(!r.$pxi().bit())); + $GPIOX::toggle_port(Self::INDEX); Ok(()) } } @@ -416,37 +324,37 @@ macro_rules! gpio { } } -gpio!(GPIO0, gpio0, gpio0, [ - Pin0: (pin0, Input), - Pin1: (pin1, Input), - Pin2: (pin2, Input), - Pin3: (pin3, Input), - Pin4: (pin4, Input), - Pin5: (pin5, Input), - Pin6: (pin6, Input), - Pin7: (pin7, Input), - Pin8: (pin8, Input), - Pin9: (pin9, Input), - Pin10: (pin10, Input), - Pin11: (pin11, Input), - Pin12: (pin12, Input), - Pin13: (pin13, Input), - Pin14: (pin14, Input), - Pin15: (pin15, Input), - Pin16: (pin16, Input), - Pin17: (pin17, Input), - Pin18: (pin18, Input), - Pin19: (pin19, Input), - Pin20: (pin20, Input), - Pin21: (pin21, Input), - Pin22: (pin22, Input), - Pin23: (pin23, Input), - Pin24: (pin24, Input), - Pin25: (pin25, Input), - Pin26: (pin26, Input), - Pin27: (pin27, Input), - Pin28: (pin28, Input), - Pin29: (pin29, Input), - Pin30: (pin30, Input), - Pin31: (pin31, Input), +gpio!(GPIO0, gpio0, [ + Pin0: (pin0, 0, Input), + Pin1: (pin1, 1, Input), + Pin2: (pin2, 2, Input), + Pin3: (pin3, 3, Input), + Pin4: (pin4, 4, Input), + Pin5: (pin5, 5, Input), + Pin6: (pin6, 6, Input), + Pin7: (pin7, 7, Input), + Pin8: (pin8, 8, Input), + Pin9: (pin9, 9, Input), + Pin10: (pin10, 10, Input), + Pin11: (pin11, 11, Input), + Pin12: (pin12, 12, Input), + Pin13: (pin13, 13, Input), + Pin14: (pin14, 14, Input), + Pin15: (pin15, 15, Input), + Pin16: (pin16, 16, Input), + Pin17: (pin17, 17, Input), + Pin18: (pin18, 18, Input), + Pin19: (pin19, 19, Input), + Pin20: (pin20, 20, Input), + Pin21: (pin21, 21, Input), + Pin22: (pin22, 22, Input), + Pin23: (pin23, 23, Input), + Pin24: (pin24, 24, Input), + Pin25: (pin25, 25, Input), + Pin26: (pin26, 26, Input), + Pin27: (pin27, 27, Input), + Pin28: (pin28, 28, Input), + Pin29: (pin29, 29, Input), + Pin30: (pin30, 30, Input), + Pin31: (pin31, 31, Input), ]); From a5d46a763bba19f98c1f42e0be93c53da74f6fb7 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 14:51:45 +0300 Subject: [PATCH 115/315] Fix bug in GPIO is_high() --- src/gpio.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 8d2345c..a6a80b6 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -278,21 +278,22 @@ macro_rules! gpio { type Error = Infallible; fn is_high(&self) -> Result { - Ok(!self.is_low()?) + Ok($GPIOX::value(Self::INDEX)) + } fn is_low(&self) -> Result { - Ok($GPIOX::value(Self::INDEX)) + Ok(!self.is_high()?) } } impl StatefulOutputPin for $PXi> { fn is_set_high(&self) -> Result { - Ok(!self.is_set_low()?) + Ok($GPIOX::value(Self::INDEX)) } fn is_set_low(&self) -> Result { - Ok($GPIOX::value(Self::INDEX)) + Ok(!self.is_set_high()?) } } From b499fa838a99e4a034d367cb592bb070a616ced6 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 14:56:38 +0300 Subject: [PATCH 116/315] Force inlining for the peripheral() method --- src/gpio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gpio.rs b/src/gpio.rs index a6a80b6..1ca9742 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -157,6 +157,7 @@ macro_rules! gpio { } impl PeripheralAccess for $GPIOX { + #[inline(always)] fn peripheral() -> &'static e310x::gpio0::RegisterBlock { unsafe { &*$GPIOX::ptr() } } From 57d96419f9bcb918e33714cd0b7e0862c6946cd7 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:12:57 +0300 Subject: [PATCH 117/315] Assume the Unknown state for all GPIOs by default --- src/gpio.rs | 71 ++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 1ca9742..c0c0cf3 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -12,6 +12,8 @@ pub trait GpioExt { fn split(self) -> Self::Parts; } +/// Unknown mode (type state) +pub struct Unknown; /// Input mode (type state) pub struct Input { @@ -145,7 +147,7 @@ macro_rules! gpio { use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::$GPIOX; - use super::{IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, + use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess}; /// GPIO parts for fine grained permission control. @@ -326,37 +328,40 @@ macro_rules! gpio { } } +// By default, all GPIOs are in the Unknown state for two reasons: +// * bootloader may reconfigure some GPIOs +// * we do not enforce any specific state in `split()` gpio!(GPIO0, gpio0, [ - Pin0: (pin0, 0, Input), - Pin1: (pin1, 1, Input), - Pin2: (pin2, 2, Input), - Pin3: (pin3, 3, Input), - Pin4: (pin4, 4, Input), - Pin5: (pin5, 5, Input), - Pin6: (pin6, 6, Input), - Pin7: (pin7, 7, Input), - Pin8: (pin8, 8, Input), - Pin9: (pin9, 9, Input), - Pin10: (pin10, 10, Input), - Pin11: (pin11, 11, Input), - Pin12: (pin12, 12, Input), - Pin13: (pin13, 13, Input), - Pin14: (pin14, 14, Input), - Pin15: (pin15, 15, Input), - Pin16: (pin16, 16, Input), - Pin17: (pin17, 17, Input), - Pin18: (pin18, 18, Input), - Pin19: (pin19, 19, Input), - Pin20: (pin20, 20, Input), - Pin21: (pin21, 21, Input), - Pin22: (pin22, 22, Input), - Pin23: (pin23, 23, Input), - Pin24: (pin24, 24, Input), - Pin25: (pin25, 25, Input), - Pin26: (pin26, 26, Input), - Pin27: (pin27, 27, Input), - Pin28: (pin28, 28, Input), - Pin29: (pin29, 29, Input), - Pin30: (pin30, 30, Input), - Pin31: (pin31, 31, Input), + Pin0: (pin0, 0, Unknown), + Pin1: (pin1, 1, Unknown), + Pin2: (pin2, 2, Unknown), + Pin3: (pin3, 3, Unknown), + Pin4: (pin4, 4, Unknown), + Pin5: (pin5, 5, Unknown), + Pin6: (pin6, 6, Unknown), + Pin7: (pin7, 7, Unknown), + Pin8: (pin8, 8, Unknown), + Pin9: (pin9, 9, Unknown), + Pin10: (pin10, 10, Unknown), + Pin11: (pin11, 11, Unknown), + Pin12: (pin12, 12, Unknown), + Pin13: (pin13, 13, Unknown), + Pin14: (pin14, 14, Unknown), + Pin15: (pin15, 15, Unknown), + Pin16: (pin16, 16, Unknown), + Pin17: (pin17, 17, Unknown), + Pin18: (pin18, 18, Unknown), + Pin19: (pin19, 19, Unknown), + Pin20: (pin20, 20, Unknown), + Pin21: (pin21, 21, Unknown), + Pin22: (pin22, 22, Unknown), + Pin23: (pin23, 23, Unknown), + Pin24: (pin24, 24, Unknown), + Pin25: (pin25, 25, Unknown), + Pin26: (pin26, 26, Unknown), + Pin27: (pin27, 27, Unknown), + Pin28: (pin28, 28, Unknown), + Pin29: (pin29, 29, Unknown), + Pin30: (pin30, 30, Unknown), + Pin31: (pin31, 31, Unknown), ]); From ffbbd4fe41f8938720f0c0efec32b1e4b6c2d0b8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:22:49 +0300 Subject: [PATCH 118/315] Improve I2C documentation --- src/i2c.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/i2c.rs b/src/i2c.rs index 7d5202a..7b27ff0 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -2,6 +2,13 @@ //! //! The SiFive Inter-Integrated Circuit (I2C) Master Interface //! is based on OpenCores® I2C Master Core. +//! +//! You can use the `I2c` interface with these I2C instances +//! +//! # I2C0 +//! - SDA: Pin 12 IOF0 +//! - SCL: Pin 13 IOF0 +//! - Interrupt::I2C0 use e310x::{I2C0, i2c0}; use core::ops::Deref; From 28f0ec69db7e1d419f3e5269b5c448bf63f454a2 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:37:43 +0300 Subject: [PATCH 119/315] Fix Serial::flush() --- src/serial.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 937868a..c806d80 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -74,11 +74,10 @@ impl Serial { let div = clocks.tlclk().0 / baud_rate.0 - 1; unsafe { uart.div.write(|w| w.bits(div)); + uart.txctrl.write(|w| w.counter().bits(1).enable().bit(true)); + uart.rxctrl.write(|w| w.enable().bit(true)); } - uart.txctrl.write(|w| w.enable().bit(true)); - uart.rxctrl.write(|w| w.enable().bit(true)); - Serial { uart, pins } } @@ -146,12 +145,11 @@ impl serial::Write for Tx { } fn flush(&mut self) -> nb::Result<(), Infallible> { - let txdata = self.uart.txdata.read(); - - if txdata.full().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { + if self.uart.ip.read().txwm().bit_is_set() { + // FIFO count is below the receive watermark (1) Ok(()) + } else { + Err(nb::Error::WouldBlock) } } } From 30423c697b8caabedf0a8669b04993f52528f83e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:38:06 +0300 Subject: [PATCH 120/315] Disable watermark interrupts in serial --- src/serial.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/serial.rs b/src/serial.rs index c806d80..18d0cda 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -73,6 +73,7 @@ impl Serial { { let div = clocks.tlclk().0 / baud_rate.0 - 1; unsafe { + uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(false)); uart.div.write(|w| w.bits(div)); uart.txctrl.write(|w| w.counter().bits(1).enable().bit(true)); uart.rxctrl.write(|w| w.enable().bit(true)); From 8ab1890ffd136e2d1abf12e77e76710630b44820 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:46:26 +0300 Subject: [PATCH 121/315] Update e310x dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 324ed45..af4f17a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.1" riscv = "0.5.0" -e310x = { version = "0.5.0", features = ["rt"] } +e310x = { version = "0.5.1", features = ["rt"] } [features] g002 = ["e310x/g002"] From f82fb7e22c68472db0b63c7f88b376a2a089d7a2 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 15:46:48 +0300 Subject: [PATCH 122/315] Bump version (0.6.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index af4f17a..9061385 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.5.1" +version = "0.6.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From b422dc2d5e41835a09ce1df1436ea95908e6736f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 16:00:53 +0300 Subject: [PATCH 123/315] 2018 edition --- Cargo.toml | 1 + src/clock.rs | 2 +- src/led.rs | 4 ++-- src/lib.rs | 3 +-- src/serial.rs | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ad53ba..67348e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "Board support crate for HiFive1 and LoFive boards" keywords = ["riscv", "register", "peripheral"] license = "ISC" +edition = "2018" [dependencies] e310x-hal = "0.5.0" diff --git a/src/clock.rs b/src/clock.rs index bbfed6a..84fb9d4 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,6 +1,6 @@ //! Board-specific clock configuration -use hal::{ +use e310x_hal::{ e310x::{PRCI, AONCLK}, clock::{Clocks, PrciExt, AonExt}, time::Hertz, diff --git a/src/led.rs b/src/led.rs index 521c050..6ee5e5a 100644 --- a/src/led.rs +++ b/src/led.rs @@ -4,9 +4,9 @@ //! - Green = Pin 19 //! - Blue = Pin 21 use embedded_hal::digital::v2::OutputPin; -use hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, +use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, OUT_XOR, IOF_EN}; -use hal::gpio::{Output, Regular, Invert}; +use e310x_hal::gpio::{Output, Regular, Invert}; /// Red LED pub type RED = Pin22>>; diff --git a/src/lib.rs b/src/lib.rs index 45e7d37..9139af0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,7 @@ #![deny(missing_docs)] #![no_std] -pub extern crate e310x_hal as hal; -extern crate embedded_hal; +pub use e310x_hal as hal; pub mod clock; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] diff --git a/src/serial.rs b/src/serial.rs index cd2aca2..b01b468 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -2,10 +2,10 @@ //! //! - Tx = Pin 17 //! - Rx = Pin 16 -use hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; -use hal::gpio::{IOF0, NoInvert}; -use hal::serial::{Tx, Rx}; -use hal::e310x::UART0; +use e310x_hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; +use e310x_hal::gpio::{IOF0, NoInvert}; +use e310x_hal::serial::{Tx, Rx}; +use e310x_hal::e310x::UART0; /// UART0 TX Pin pub type TxPin = Pin17>; From f9d470329617bf857f24ca8bc2d1db39c8f89cf1 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 16:02:36 +0300 Subject: [PATCH 124/315] Update e310x-hal dependency --- Cargo.toml | 2 +- src/led.rs | 28 +++++----------------------- src/serial.rs | 10 ++++------ 3 files changed, 10 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 67348e9..9492699 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.5.0" +e310x-hal = "0.6.0" embedded-hal = "0.2.3" [features] diff --git a/src/led.rs b/src/led.rs index 6ee5e5a..9686f5d 100644 --- a/src/led.rs +++ b/src/led.rs @@ -4,8 +4,7 @@ //! - Green = Pin 19 //! - Blue = Pin 21 use embedded_hal::digital::v2::OutputPin; -use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22, OUTPUT_EN, DRIVE, - OUT_XOR, IOF_EN}; +use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22}; use e310x_hal::gpio::{Output, Regular, Invert}; /// Red LED @@ -19,29 +18,12 @@ pub type BLUE = Pin21>>; /// Returns RED, GREEN and BLUE LEDs. pub fn rgb( - red: Pin22, green: Pin19, blue: Pin21, - output_en: &mut OUTPUT_EN, drive: &mut DRIVE, - out_xor: &mut OUT_XOR, iof_en: &mut IOF_EN + red: Pin22, green: Pin19, blue: Pin21 ) -> (RED, GREEN, BLUE) { - let red: RED = red.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); - let green: GREEN = green.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); - let blue: BLUE = blue.into_inverted_output( - output_en, - drive, - out_xor, - iof_en, - ); + let red: RED = red.into_inverted_output(); + let green: GREEN = green.into_inverted_output(); + let blue: BLUE = blue.into_inverted_output(); (red, green, blue) } diff --git a/src/serial.rs b/src/serial.rs index b01b468..cbfc842 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -2,7 +2,7 @@ //! //! - Tx = Pin 17 //! - Rx = Pin 16 -use e310x_hal::gpio::gpio0::{Pin16, Pin17, OUT_XOR, IOF_SEL, IOF_EN}; +use e310x_hal::gpio::gpio0::{Pin16, Pin17}; use e310x_hal::gpio::{IOF0, NoInvert}; use e310x_hal::serial::{Tx, Rx}; use e310x_hal::e310x::UART0; @@ -18,12 +18,10 @@ pub type RX = Rx; /// Return TX, RX pins. pub fn tx_rx( - tx: Pin17, rx: Pin16, - out_xor: &mut OUT_XOR, iof_sel: &mut IOF_SEL, - iof_en: &mut IOF_EN + tx: Pin17, rx: Pin16 ) -> (TxPin, RxPin) { - let tx: TxPin = tx.into_iof0(out_xor, iof_sel, iof_en); - let rx: RxPin = rx.into_iof0(out_xor, iof_sel, iof_en); + let tx: TxPin = tx.into_iof0(); + let rx: RxPin = rx.into_iof0(); (tx, rx) } From 3fbdce1cc08c0c54335e6e13cf833c256266255d Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 16:10:49 +0300 Subject: [PATCH 125/315] Replace serial methods with stdout --- Cargo.toml | 2 + src/lib.rs | 7 ++-- src/serial.rs | 27 -------------- src/stdout.rs | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 30 deletions(-) delete mode 100644 src/serial.rs create mode 100644 src/stdout.rs diff --git a/Cargo.toml b/Cargo.toml index 9492699..c62c96e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ edition = "2018" [dependencies] e310x-hal = "0.6.0" embedded-hal = "0.2.3" +riscv = "0.5.2" +nb = "0.1.2" [features] board-hifive1 = [] diff --git a/src/lib.rs b/src/lib.rs index 9139af0..856b050 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,10 +6,11 @@ pub use e310x_hal as hal; pub mod clock; + #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub mod led; -pub mod serial; - #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub use led::{RED, GREEN, BLUE, rgb, Led}; -pub use serial::{TX, RX, TxPin, RxPin, tx_rx}; + +pub mod stdout; +pub use stdout::configure as configure_stdout; diff --git a/src/serial.rs b/src/serial.rs deleted file mode 100644 index cbfc842..0000000 --- a/src/serial.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Single UART hooked up to FTDI -//! -//! - Tx = Pin 17 -//! - Rx = Pin 16 -use e310x_hal::gpio::gpio0::{Pin16, Pin17}; -use e310x_hal::gpio::{IOF0, NoInvert}; -use e310x_hal::serial::{Tx, Rx}; -use e310x_hal::e310x::UART0; - -/// UART0 TX Pin -pub type TxPin = Pin17>; -/// UART0 RX Pin -pub type RxPin = Pin16>; -/// UART0 TX -pub type TX = Tx; -/// UART0 RX -pub type RX = Rx; - -/// Return TX, RX pins. -pub fn tx_rx( - tx: Pin17, rx: Pin16 -) -> (TxPin, RxPin) -{ - let tx: TxPin = tx.into_iof0(); - let rx: RxPin = rx.into_iof0(); - (tx, rx) -} diff --git a/src/stdout.rs b/src/stdout.rs new file mode 100644 index 0000000..147a605 --- /dev/null +++ b/src/stdout.rs @@ -0,0 +1,100 @@ +//! Stdout based on the UART hooked up to FTDI or J-Link + +use core::fmt; +use nb::block; +use riscv::interrupt; +use e310x_hal::{ + serial::{Serial, Tx}, + gpio::gpio0::{Pin17, Pin16}, + time::Bps, + clock::Clocks, + e310x::UART0, + prelude::* +}; + + +static mut STDOUT: Option = None; + + +struct SerialWrapper(Tx); + +impl core::fmt::Write for SerialWrapper { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.as_bytes() { + if *byte == '\n' as u8 { + let res = block!(self.0.write('\r' as u8)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + } + + let res = block!(self.0.write(*byte)); + + if res.is_err() { + return Err(::core::fmt::Error); + } + } + Ok(()) + } +} + +/// Configures stdout +pub fn configure( + uart: UART0, tx: Pin17, rx: Pin16, + baud_rate: Bps, clocks: Clocks +) { + let tx = tx.into_iof0(); + let rx = rx.into_iof0(); + let serial = Serial::new(uart, (tx, rx), baud_rate, clocks); + let (tx, _) = serial.split(); + + interrupt::free(|_| { + unsafe { + STDOUT.replace(SerialWrapper(tx)); + } + }) +} + +/// Writes string to stdout +pub fn write_str(s: &str) { + interrupt::free(|_| unsafe { + if let Some(stdout) = STDOUT.as_mut() { + let _ = stdout.write_str(s); + } + }) +} + +/// Writes formatted string to stdout +pub fn write_fmt(args: fmt::Arguments) { + interrupt::free(|_| unsafe { + if let Some(stdout) = STDOUT.as_mut() { + let _ = stdout.write_fmt(args); + } + }) +} + +/// Macro for printing to the serial standard output +#[macro_export] +macro_rules! sprint { + ($s:expr) => { + $crate::stdout::write_str($s) + }; + ($($tt:tt)*) => { + $crate::stdout::write_fmt(format_args!($($tt)*)) + }; +} + +/// Macro for printing to the serial standard output, with a newline. +#[macro_export] +macro_rules! sprintln { + () => { + $crate::stdout::write_str("\n") + }; + ($s:expr) => { + $crate::stdout::write_str(concat!($s, "\n")) + }; + ($s:expr, $($tt:tt)*) => { + $crate::stdout::write_fmt(format_args!(concat!($s, "\n"), $($tt)*)) + }; +} From 8c0cffb805127bd090049bdd291cfc3d68a92ada Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 17:20:33 +0300 Subject: [PATCH 126/315] Reexport clock::configure function --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 856b050..5d9b14d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub use e310x_hal as hal; pub mod clock; +pub use clock::configure as configure_clocks; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub mod led; From 2ea9db6a68385a5729fbd2a203806f1a4ec551fd Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 17:22:08 +0300 Subject: [PATCH 127/315] Remove outdated hacks from .travis.yml --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8821911..1e9dc7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,9 +19,6 @@ script: cache: cargo -before_cache: - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo branches: only: From 1bf4073d64db241ed3a68c3bb34084bcfecf5d26 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 15 Jun 2019 17:28:28 +0300 Subject: [PATCH 128/315] Bump version (0.6.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c62c96e..4ead38f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.5.0" +version = "0.6.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From da7c7b128d90291bc42511d2788adeea80f82397 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 17 Jun 2019 00:11:00 +0300 Subject: [PATCH 129/315] Implement more efficient blocking SPI interfaces --- src/spi.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index b34b671..a08a018 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -207,10 +207,134 @@ impl embedded_hal::spi::FullDuplex for Spi { } } -impl embedded_hal::blocking::spi::transfer::Default for Spi {} +impl embedded_hal::blocking::spi::Transfer for Spi { + type Error = Infallible; + + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w[u8], Self::Error> { + // Save watermark levels + let txmark = self.spi.txmark.read().value().bits(); + let rxmark = self.spi.rxmark.read().value().bits(); + + // Set watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + + // Ensure that RX FIFO is empty + while self.spi.ip.read().rxwm().bit_is_set() { + let _ = self.spi.rxdata.read(); + } + + let mut iwrite = 0; + let mut iread = 0; + while iwrite < words.len() || iread < words.len() { + if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = unsafe { words.get_unchecked(iwrite) }; + iwrite += 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + } + + if iread < iwrite && self.spi.ip.read().rxwm().bit_is_set() { + let byte = self.spi.rxdata.read().data().bits(); + unsafe { *words.get_unchecked_mut(iread) = byte }; + iread += 1; + } + } + + // Restore watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); + + Ok(words) + } +} + +impl embedded_hal::blocking::spi::Write for Spi { + type Error = Infallible; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + // Save watermark levels + let txmark = self.spi.txmark.read().value().bits(); + let rxmark = self.spi.rxmark.read().value().bits(); + + // Set watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + + // Ensure that RX FIFO is empty + while self.spi.ip.read().rxwm().bit_is_set() { + let _ = self.spi.rxdata.read(); + } -impl embedded_hal::blocking::spi::write::Default for Spi {} + let mut iwrite = 0; + let mut iread = 0; + while iwrite < words.len() || iread < words.len() { + if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = unsafe { words.get_unchecked(iwrite) }; + iwrite += 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + } + + if iread < iwrite && self.spi.ip.read().rxwm().bit_is_set() { + let _ = self.spi.rxdata.read(); + iread += 1; + } + } + + // Restore watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); + + Ok(()) + } +} + +impl embedded_hal::blocking::spi::WriteIter for Spi { + type Error = (); + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator + { + let mut iter = words.into_iter(); + + // Save watermark levels + let txmark = self.spi.txmark.read().value().bits(); + let rxmark = self.spi.rxmark.read().value().bits(); + // Set watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + + // Ensure that RX FIFO is empty + while self.spi.ip.read().rxwm().bit_is_set() { + let _ = self.spi.rxdata.read(); + } + + let mut read_count = 0; + let mut has_data = true; + while has_data || read_count > 0 { + if has_data && self.spi.txdata.read().full().bit_is_clear() { + if let Some(byte) = iter.next() { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + read_count += 1; + } else { + has_data = false; + } + } + + if read_count > 0 && self.spi.ip.read().rxwm().bit_is_set() { + let _ = self.spi.rxdata.read(); + read_count -= 1; + } + } + + // Restore watermark levels + self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); + self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); + + Ok(()) + } +} // Backward compatibility From 55d45d712005fa3d197b30e8a7477217d9aa1b73 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 23 Jun 2019 14:44:01 -0600 Subject: [PATCH 130/315] add Sleep as DelayMs implementation using mtimecmp and wfi() --- src/delay.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index f7b18c2..b2c4097 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,9 +1,10 @@ //! # Delays use embedded_hal::blocking::delay::DelayMs; -use crate::clint::MTIME; +use crate::clint::{MTIME, MTIMECMP}; +use riscv::register::{mie, mip}; -/// Machine timer (mtime) as a delay provider +/// Machine timer (mtime) as a busyloop delay provider pub struct Delay; impl Delay { @@ -34,3 +35,57 @@ impl DelayMs for Delay { self.delay_ms(u32::from(ms)); } } + +/// Machine timer (mtime) as a sleep delay provider using mtimecmp +pub struct Sleep { + mtimecmp: MTIMECMP +} + +impl Sleep { + /// Constructs a delay provider using mtimecmp register to sleep + pub fn new(mtimecmp: MTIMECMP) -> Self { + unsafe { + mie::set_mtimer(); + } + + Sleep { + mtimecmp + } + } +} + +impl DelayMs for Sleep { + fn delay_ms(&mut self, ms: u32) { + let ticks = (ms as u64) * 65536 / 1000; + let t = MTIME.mtime() + ticks; + + self.mtimecmp.set_mtimecmp(t); + + // Wait For Interrupt will put CPU to sleep until an interrupt hits + // in our case when internal timer mtime value >= mtimecmp value + // after which empty handler gets called and we go into the + // next iteration of this loop + loop { + unsafe { + riscv::asm::wfi(); + } + + // check if we got the right interrupt cause, otherwise just loop back to wfi + if mip::read().mtimer() { + break; + } + } + } +} + +impl DelayMs for Sleep { + fn delay_ms(&mut self, ms: u16) { + self.delay_ms(u32::from(ms)); + } +} + +impl DelayMs for Sleep { + fn delay_ms(&mut self, ms: u8) { + self.delay_ms(u32::from(ms)); + } +} From cd3f8bd88329762ef43b7fc066a47f9fd41789e7 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 23 Jun 2019 15:22:14 -0600 Subject: [PATCH 131/315] fix Delay and Sleep ticks calculation --- src/delay.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index b2c4097..59fe84f 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -2,6 +2,7 @@ use embedded_hal::blocking::delay::DelayMs; use crate::clint::{MTIME, MTIMECMP}; +use crate::time::Hertz; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider @@ -16,7 +17,7 @@ impl Delay { impl DelayMs for Delay { fn delay_ms(&mut self, ms: u32) { - let ticks = (ms as u64) * 65536 / 1000; + let ticks = (ms as u64) * 32768 / 1000; let mtime = MTIME; let t = mtime.mtime() + ticks; @@ -38,28 +39,31 @@ impl DelayMs for Delay { /// Machine timer (mtime) as a sleep delay provider using mtimecmp pub struct Sleep { + clock_freq: u32, mtimecmp: MTIMECMP } impl Sleep { /// Constructs a delay provider using mtimecmp register to sleep - pub fn new(mtimecmp: MTIMECMP) -> Self { - unsafe { - mie::set_mtimer(); - } - + pub fn new(mtimecmp: MTIMECMP, clock_freq: Hertz) -> Self { Sleep { - mtimecmp + clock_freq: clock_freq.0, + mtimecmp, } } } impl DelayMs for Sleep { fn delay_ms(&mut self, ms: u32) { - let ticks = (ms as u64) * 65536 / 1000; + let ticks = (ms as u64) * (self.clock_freq as u64) / 1000; let t = MTIME.mtime() + ticks; self.mtimecmp.set_mtimecmp(t); + + // Enable timer interrupt + unsafe { + mie::set_mtimer(); + } // Wait For Interrupt will put CPU to sleep until an interrupt hits // in our case when internal timer mtime value >= mtimecmp value @@ -75,6 +79,11 @@ impl DelayMs for Sleep { break; } } + + // Clear timer interrupt + unsafe { + mie::clear_mtimer(); + } } } From f41c1dca9714c938ce2ab4888e6fbab36d319a34 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 23 Jun 2019 15:22:31 -0600 Subject: [PATCH 132/315] update dependencies + bump version --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9061385..b20f64c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.6.0" +version = "0.6.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -11,8 +11,8 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } -nb = "0.1.1" -riscv = "0.5.0" +nb = "0.1.2" +riscv = "0.5.2" e310x = { version = "0.5.1", features = ["rt"] } [features] From ff78049936a7c28abd45bd3feea8f0e889107320 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 24 Jun 2019 00:32:56 +0300 Subject: [PATCH 133/315] Use Clocks instead of passed clock frequency --- src/delay.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index 59fe84f..881b201 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -2,7 +2,7 @@ use embedded_hal::blocking::delay::DelayMs; use crate::clint::{MTIME, MTIMECMP}; -use crate::time::Hertz; +use crate::clock::Clocks; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider @@ -45,9 +45,9 @@ pub struct Sleep { impl Sleep { /// Constructs a delay provider using mtimecmp register to sleep - pub fn new(mtimecmp: MTIMECMP, clock_freq: Hertz) -> Self { + pub fn new(mtimecmp: MTIMECMP, clocks: Clocks) -> Self { Sleep { - clock_freq: clock_freq.0, + clock_freq: clocks.lfclk().0, mtimecmp, } } From cdbbf18ccfea9eab676efbc9d36b9f80a630f865 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 20:34:43 +0300 Subject: [PATCH 134/315] Implement read-only/write-only SPI pin combinations, enforce NoInvert for SPI pins --- src/spi.rs | 70 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index a08a018..2e7d16f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -27,7 +27,6 @@ use core::convert::Infallible; use core::ops::Deref; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::e310x::{QSPI0, QSPI1, QSPI2, qspi0}; -use crate::gpio::{IOF0, gpio0}; use crate::clock::Clocks; use crate::time::Hertz; use nb; @@ -36,6 +35,7 @@ use nb; /// SPI pins - DO NOT IMPLEMENT THIS TRAIT /// /// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) and (MOSI, MISO, SCK, SS) +/// and combinations without MOSI/MISO pub trait Pins { #[doc(hidden)] const CS_INDEX: Option; @@ -47,33 +47,53 @@ impl Pins for () { } /* SPI1 pins */ -impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>) { - const CS_INDEX: Option = None; -} - -impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin2>) { - const CS_INDEX: Option = Some(0); -} - -impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin8>) { - const CS_INDEX: Option = Some(1); -} - -impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin9>) { - const CS_INDEX: Option = Some(2); -} - -impl Pins for (gpio0::Pin3>, gpio0::Pin4>, gpio0::Pin5>, gpio0::Pin10>) { - const CS_INDEX: Option = Some(3); +mod spi1_impl { + use crate::gpio::{NoInvert, IOF0}; + use crate::gpio::gpio0; + use super::{Pins, QSPI1}; + + type MOSI = gpio0::Pin3>; + type MISO = gpio0::Pin4>; + type SCK = gpio0::Pin5>; + type SS0 = gpio0::Pin2>; + type SS1 = gpio0::Pin8>; + type SS2 = gpio0::Pin9>; + type SS3 = gpio0::Pin10>; + + impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } + impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } + impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } + impl Pins for (MOSI, MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for (MOSI, (), SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for ((), MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for (MOSI, MISO, SCK, SS1) { const CS_INDEX: Option = Some(1); } + impl Pins for (MOSI, (), SCK, SS1) { const CS_INDEX: Option = Some(1); } + impl Pins for ((), MISO, SCK, SS1) { const CS_INDEX: Option = Some(1); } + impl Pins for (MOSI, MISO, SCK, SS2) { const CS_INDEX: Option = Some(2); } + impl Pins for (MOSI, (), SCK, SS2) { const CS_INDEX: Option = Some(2); } + impl Pins for ((), MISO, SCK, SS2) { const CS_INDEX: Option = Some(2); } + impl Pins for (MOSI, MISO, SCK, SS3) { const CS_INDEX: Option = Some(3); } + impl Pins for (MOSI, (), SCK, SS3) { const CS_INDEX: Option = Some(3); } + impl Pins for ((), MISO, SCK, SS3) { const CS_INDEX: Option = Some(3); } } /* SPI2 pins */ -impl Pins for (gpio0::Pin27>, gpio0::Pin28>, gpio0::Pin29>) { - const CS_INDEX: Option = None; -} - -impl Pins for (gpio0::Pin27>, gpio0::Pin28>, gpio0::Pin29>, gpio0::Pin26>) { - const CS_INDEX: Option = Some(0); +mod spi2_impl { + use crate::gpio::{NoInvert, IOF0}; + use crate::gpio::gpio0; + use super::{Pins, QSPI2}; + + type MOSI = gpio0::Pin27>; + type MISO = gpio0::Pin28>; + type SCK = gpio0::Pin29>; + type SS0 = gpio0::Pin26>; + + impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } + impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } + impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } + impl Pins for (MOSI, MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for (MOSI, (), SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for ((), MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } } From 45228fc32808bd816685e617f52d75e79fb606eb Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 20:38:31 +0300 Subject: [PATCH 135/315] Use Infallible error type for embedded_hal::blocking::spi::WriteIter --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index 2e7d16f..15fd4b7 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -309,7 +309,7 @@ impl embedded_hal::blocking::spi::Write for Spi } impl embedded_hal::blocking::spi::WriteIter for Spi { - type Error = (); + type Error = Infallible; fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where From 578e3194efdd439224d0a9073202b63e112d7ef4 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 20:41:30 +0300 Subject: [PATCH 136/315] Update docs --- src/spi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 15fd4b7..07b60d0 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -10,13 +10,13 @@ //! - MISO: Pin 4 IOF0 //! - SCK: Pin 5 IOF0 //! - SS0: Pin 2 IOF0 -//! - SS1: Pin 8 IOF0 +//! - SS1: Pin 8 IOF0 (not connected to package in FE310) //! - SS2: Pin 9 IOF0 //! - SS3: Pin 10 IOF0 //! - Interrupt::QSPI1 //! //! # QSPI2 -//! *Warning:* QSPI2 pins are not connected to package in FE310-G000 +//! *Warning:* QSPI2 pins are not connected to package in FE310 //! - MOSI: Pin 27 IOF0 //! - MISO: Pin 28 IOF0 //! - SCK: Pin 29 IOF0 From 3d3085b02b4ef68e3268d512cf20b3a1646a3ffe Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 22:30:54 +0300 Subject: [PATCH 137/315] Add an abstraction layer for the device resources --- src/lib.rs | 3 ++ src/resources.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/resources.rs diff --git a/src/lib.rs b/src/lib.rs index 4440b94..0367f13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod clint; pub mod clock; pub mod delay; pub mod gpio; +pub mod resources; pub mod plic; pub mod prelude; pub mod rtc; @@ -23,3 +24,5 @@ pub mod wdog; #[cfg(feature = "g002")] pub mod i2c; + +pub use resources::{Peripherals, DeviceResources}; diff --git a/src/resources.rs b/src/resources.rs new file mode 100644 index 0000000..eb88947 --- /dev/null +++ b/src/resources.rs @@ -0,0 +1,105 @@ +//! Device resources + +use e310x::{ + CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2 +}; +#[cfg(feature = "g002")] +use e310x::{I2C0, UART1}; +use crate::gpio::{GpioExt, gpio0}; + +/// All the peripherals except GPIO +#[allow(non_snake_case)] +pub struct Peripherals { + /// CLINT peripheral + pub CLINT: CLINT, + /// PLIC peripheral + pub PLIC: PLIC, + /// WDOG peripheral + pub WDOG: WDOG, + /// RTC peripheral + pub RTC: RTC, + /// AONCLK peripheral + pub AONCLK: AONCLK, + /// BACKUP peripheral + pub BACKUP: BACKUP, + /// PMU peripheral + pub PMU: PMU, + /// PRCI peripheral + pub PRCI: PRCI, + /// OTP peripheral + pub OTP: OTP, + + /// UART0 peripheral + pub UART0: UART0, + #[cfg(feature = "g002")] + /// UART1 peripheral + pub UART1: UART1, + + /// QSPI1 peripheral + pub QSPI1: QSPI1, + + #[cfg(feature = "g002")] + /// I2C0 peripheral + pub I2C0: I2C0, + + /// PWM0 peripheral + pub PWM0: PWM0, + /// PWM1 peripheral + pub PWM1: PWM1, + /// PWM2 peripheral + pub PWM2: PWM2, +} + +/// Device resources +pub struct DeviceResources { + /// Device peripherals + pub peripherals: Peripherals, + + /// Device pins + pub pins: gpio0::Parts, +} + +impl DeviceResources { + fn construct(p: e310x::Peripherals) -> Self { + let peripherals = Peripherals { + CLINT: p.CLINT, + PLIC: p.PLIC, + WDOG: p.WDOG, + RTC: p.RTC, + AONCLK: p.AONCLK, + BACKUP: p.BACKUP, + PMU: p.PMU, + PRCI: p.PRCI, + OTP: p.OTP, + + UART0: p.UART0, + #[cfg(feature = "g002")] + UART1: p.UART1, + + QSPI1: p.QSPI1, + + #[cfg(feature = "g002")] + I2C0: p.I2C0, + + PWM0: p.PWM0, + PWM1: p.PWM1, + PWM2: p.PWM2, + }; + + DeviceResources { + peripherals, + pins: p.GPIO0.split(), + } + } + + /// Returns all the device resources *once* + #[inline] + pub fn take() -> Option { + e310x::Peripherals::take().map(DeviceResources::construct) + } + + /// Unchecked version of `DeviceResources::take` + pub unsafe fn steal() -> Self { + DeviceResources::construct(e310x::Peripherals::steal()) + } +} From aac0379a8e503d0b3b1cf269f02884662dcf135a Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 22:48:10 +0300 Subject: [PATCH 138/315] Fix docs --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index 07b60d0..5a3b1ff 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1,6 +1,6 @@ //! # Serial Peripheral Interface //! -//! You can use the `FullDuplex` interface with these SPI instances +//! You can use the `Spi` interface with these SPI instances //! //! # QSPI0 //! - Interrupt::QSPI0 From 26477aa150a6f03decec164c7b6f133dc9a9d07f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 22:50:05 +0300 Subject: [PATCH 139/315] Add forgotten QSPI0 peripheral --- src/resources.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/resources.rs b/src/resources.rs index eb88947..113dc50 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,13 +1,13 @@ //! Device resources use e310x::{ - CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2 + CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0 }; #[cfg(feature = "g002")] use e310x::{I2C0, UART1}; use crate::gpio::{GpioExt, gpio0}; -/// All the peripherals except GPIO +/// All the peripherals except GPIO0 and QSPI2 #[allow(non_snake_case)] pub struct Peripherals { /// CLINT peripheral @@ -35,6 +35,8 @@ pub struct Peripherals { /// UART1 peripheral pub UART1: UART1, + /// QSPI0 peripheral + pub QSPI0: QSPI0, /// QSPI1 peripheral pub QSPI1: QSPI1, @@ -76,6 +78,7 @@ impl DeviceResources { #[cfg(feature = "g002")] UART1: p.UART1, + QSPI0: p.QSPI0, QSPI1: p.QSPI1, #[cfg(feature = "g002")] From 6df3f209c9a8c6c567a32b363a82a310ca88b848 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:06:59 +0300 Subject: [PATCH 140/315] Resources refactoring --- src/lib.rs | 2 +- src/resources.rs | 89 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0367f13..f26d679 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,4 +25,4 @@ pub mod wdog; #[cfg(feature = "g002")] pub mod i2c; -pub use resources::{Peripherals, DeviceResources}; +pub use resources::DeviceResources; diff --git a/src/resources.rs b/src/resources.rs index 113dc50..447ee38 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,15 +1,13 @@ //! Device resources -use e310x::{ - CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0 -}; +use e310x::{CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0, GPIO0}; #[cfg(feature = "g002")] use e310x::{I2C0, UART1}; -use crate::gpio::{GpioExt, gpio0}; +use crate::gpio::{GpioExt, gpio0::*, Unknown}; -/// All the peripherals except GPIO0 and QSPI2 +/// Device peripherals available in a 48QFN package, except GPIO0 #[allow(non_snake_case)] -pub struct Peripherals { +pub struct DevicePeripherals { /// CLINT peripheral pub CLINT: CLINT, /// PLIC peripheral @@ -52,18 +50,87 @@ pub struct Peripherals { pub PWM2: PWM2, } +/// Device GPIO pins available in a 48QFN package +pub struct DeviceGpioPins { + /// GPIO 0, package pin 25 + pub pin0: Pin0, + /// GPIO 1, package pin 26 + pub pin1: Pin1, + /// GPIO 2, package pin 27 + pub pin2: Pin2, + /// GPIO 3, package pin 28 + pub pin3: Pin3, + /// GPIO 4, package pin 29 + pub pin4: Pin4, + /// GPIO 5, package pin 31 + pub pin5: Pin5, + /// GPIO 9, package pin 33 + pub pin9: Pin9, + /// GPIO 10, package pin 34 + pub pin10: Pin10, + /// GPIO 11, package pin 35 + pub pin11: Pin11, + /// GPIO 12, package pin 36 + pub pin12: Pin12, + /// GPIO 13, package pin 37 + pub pin13: Pin13, + /// GPIO 16, package pin 38 + pub pin16: Pin16, + /// GPIO 17, package pin 39 + pub pin17: Pin17, + /// GPIO 18, package pin 40 + pub pin18: Pin18, + /// GPIO 19, package pin 41 + pub pin19: Pin19, + /// GPIO 20, package pin 42 + pub pin20: Pin20, + /// GPIO 21, package pin 43 + pub pin21: Pin21, + /// GPIO 22, package pin 44 + pub pin22: Pin22, + /// GPIO 23, package pin 45 + pub pin23: Pin23, +} + +impl From for DeviceGpioPins { + fn from(gpio: GPIO0) -> Self { + let parts = gpio.split(); + DeviceGpioPins { + pin0: parts.pin0, + pin1: parts.pin1, + pin2: parts.pin2, + pin3: parts.pin3, + pin4: parts.pin4, + pin5: parts.pin5, + pin9: parts.pin9, + pin10: parts.pin10, + pin11: parts.pin11, + pin12: parts.pin12, + pin13: parts.pin13, + pin16: parts.pin16, + pin17: parts.pin17, + pin18: parts.pin18, + pin19: parts.pin19, + pin20: parts.pin20, + pin21: parts.pin21, + pin22: parts.pin22, + pin23: parts.pin23 + } + } +} + /// Device resources pub struct DeviceResources { /// Device peripherals - pub peripherals: Peripherals, + pub peripherals: DevicePeripherals, - /// Device pins - pub pins: gpio0::Parts, + /// Device GPIO pins + pub pins: DeviceGpioPins, } impl DeviceResources { fn construct(p: e310x::Peripherals) -> Self { - let peripherals = Peripherals { + let peripherals = DevicePeripherals { CLINT: p.CLINT, PLIC: p.PLIC, WDOG: p.WDOG, @@ -91,7 +158,7 @@ impl DeviceResources { DeviceResources { peripherals, - pins: p.GPIO0.split(), + pins: p.GPIO0.into(), } } From beab04f2a3bdd07fc1ca429926ada439d3b9e732 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:12:23 +0300 Subject: [PATCH 141/315] Rename resources to device --- src/{resources.rs => device.rs} | 0 src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{resources.rs => device.rs} (100%) diff --git a/src/resources.rs b/src/device.rs similarity index 100% rename from src/resources.rs rename to src/device.rs diff --git a/src/lib.rs b/src/lib.rs index f26d679..bd058d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod clint; pub mod clock; pub mod delay; pub mod gpio; -pub mod resources; +pub mod device; pub mod plic; pub mod prelude; pub mod rtc; @@ -25,4 +25,4 @@ pub mod wdog; #[cfg(feature = "g002")] pub mod i2c; -pub use resources::DeviceResources; +pub use device::DeviceResources; From f590b2f8989c340d865f3e0f397957e59e8d41c6 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:17:11 +0300 Subject: [PATCH 142/315] Update docs --- src/device.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/device.rs b/src/device.rs index 447ee38..e2a6381 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,4 +1,4 @@ -//! Device resources +//! Device resources available in FE310-G000 and FE310-G002 chip packages use e310x::{CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0, GPIO0}; #[cfg(feature = "g002")] @@ -30,7 +30,7 @@ pub struct DevicePeripherals { /// UART0 peripheral pub UART0: UART0, #[cfg(feature = "g002")] - /// UART1 peripheral + /// UART1 peripheral (FE310-G002 only) pub UART1: UART1, /// QSPI0 peripheral @@ -39,7 +39,7 @@ pub struct DevicePeripherals { pub QSPI1: QSPI1, #[cfg(feature = "g002")] - /// I2C0 peripheral + /// I2C0 peripheral (FE310-G002 only) pub I2C0: I2C0, /// PWM0 peripheral @@ -119,7 +119,7 @@ impl From for DeviceGpioPins { } } -/// Device resources +/// Device resources available in a 48QFN package pub struct DeviceResources { /// Device peripherals pub peripherals: DevicePeripherals, From 85fc8d4d5017bf1b3fc0210d113f268f2fdbac58 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:25:54 +0300 Subject: [PATCH 143/315] Refactoring: implement From for DeviceResources --- src/device.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/device.rs b/src/device.rs index e2a6381..5ff8cc9 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,6 +1,6 @@ //! Device resources available in FE310-G000 and FE310-G002 chip packages -use e310x::{CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0, GPIO0}; +use e310x::{Peripherals, CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0, GPIO0}; #[cfg(feature = "g002")] use e310x::{I2C0, UART1}; use crate::gpio::{GpioExt, gpio0::*, Unknown}; @@ -128,8 +128,8 @@ pub struct DeviceResources { pub pins: DeviceGpioPins, } -impl DeviceResources { - fn construct(p: e310x::Peripherals) -> Self { +impl From for DeviceResources { + fn from(p: Peripherals) -> Self { let peripherals = DevicePeripherals { CLINT: p.CLINT, PLIC: p.PLIC, @@ -161,15 +161,17 @@ impl DeviceResources { pins: p.GPIO0.into(), } } +} +impl DeviceResources { /// Returns all the device resources *once* #[inline] pub fn take() -> Option { - e310x::Peripherals::take().map(DeviceResources::construct) + e310x::Peripherals::take().map(DeviceResources::from) } /// Unchecked version of `DeviceResources::take` pub unsafe fn steal() -> Self { - DeviceResources::construct(e310x::Peripherals::steal()) + e310x::Peripherals::steal().into() } } From 09a5fc9c575efe0f43e8b611f4c4109b4bc53324 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:29:03 +0300 Subject: [PATCH 144/315] Apply rustfmt --- src/device.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/device.rs b/src/device.rs index 5ff8cc9..c10fe1b 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,9 +1,12 @@ //! Device resources available in FE310-G000 and FE310-G002 chip packages -use e310x::{Peripherals, CLINT, PLIC, WDOG, RTC, AONCLK, BACKUP, PMU, PRCI, OTP, UART0, PWM0, QSPI1, PWM1, PWM2, QSPI0, GPIO0}; +use crate::gpio::{gpio0::*, GpioExt, Unknown}; +use e310x::{ + Peripherals, AONCLK, BACKUP, CLINT, GPIO0, OTP, PLIC, PMU, PRCI, PWM0, PWM1, PWM2, QSPI0, + QSPI1, RTC, UART0, WDOG, +}; #[cfg(feature = "g002")] use e310x::{I2C0, UART1}; -use crate::gpio::{GpioExt, gpio0::*, Unknown}; /// Device peripherals available in a 48QFN package, except GPIO0 #[allow(non_snake_case)] @@ -114,7 +117,7 @@ impl From for DeviceGpioPins { pin20: parts.pin20, pin21: parts.pin21, pin22: parts.pin22, - pin23: parts.pin23 + pin23: parts.pin23, } } } From 120589ffde7774be7faa4ebe2def31b365276e7d Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:39:02 +0300 Subject: [PATCH 145/315] Implement more reliable mtimecmp update Closes #19 --- src/clint.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/clint.rs b/src/clint.rs index 8cb78c5..fd36183 100644 --- a/src/clint.rs +++ b/src/clint.rs @@ -83,8 +83,10 @@ impl MTIMECMP { /// Write mtimecmp and mtimecmph registers. pub fn set_mtimecmp(&mut self, value: u64) { - self.set_mtimecmp_hi((value >> 32) as u32); - self.set_mtimecmp_lo(value as u32); + // Volume II: RISC-V Privileged Architectures V1.10 p.31, figure 3.15 + self.set_mtimecmp_lo(0xffff_ffff); // No smaller than old value + self.set_mtimecmp_hi((value >> 32) as u32); // New value + self.set_mtimecmp_lo(value as u32); // New value } } From e4f774dad1f4eadd44d9260a52aa3e87647e69d2 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 2 Jul 2019 23:55:39 +0300 Subject: [PATCH 146/315] CLINT refactoring --- src/clint.rs | 126 ++++++++++++------------------------------------- src/clock.rs | 15 +++--- src/prelude.rs | 1 - 3 files changed, 37 insertions(+), 105 deletions(-) diff --git a/src/clint.rs b/src/clint.rs index fd36183..c3f0e94 100644 --- a/src/clint.rs +++ b/src/clint.rs @@ -1,6 +1,5 @@ -//! Clint +//! Core-Local Interruptor -use riscv::register::{mcycle, mcycleh, minstret, minstreth, mie, mip}; use e310x::CLINT; macro_rules! read64 { @@ -15,16 +14,27 @@ macro_rules! read64 { } } -/// ClintExt trait extends the CLINT peripheral. -pub trait ClintExt { - /// The parts to split the GPIO into. - type Parts; +/// Opaque msip register +pub struct MSIP { + _0: (), +} - /// Splits the GPIO block into independent pins and registers. - fn split(self) -> Self::Parts; +impl MSIP { + /// Set msip register value + pub fn set_value(&mut self, value: bool) { + unsafe { + (*CLINT::ptr()).msip.write(|w| { + if value { + w.bits(1) + } else { + w.bits(0) + } + }) + } + } } -/// Opaque MTIME register +/// Opaque mtime register pub struct MTIME; impl MTIME { @@ -46,7 +56,7 @@ impl MTIME { } } -/// Opaque MTIMECMP register +/// Opaque mtimecmp register pub struct MTIMECMP { _0: (), } @@ -90,100 +100,22 @@ impl MTIMECMP { } } -/// Opaque mcycle register -pub struct MCYCLE { - _0: (), -} - -impl MCYCLE { - /// Read mcycle register. - #[inline] - pub fn mcycle_lo(&self) -> u32 { - mcycle::read() as u32 - } - - /// Read mcycleh register. - #[inline] - pub fn mcycle_hi(&self) -> u32 { - mcycleh::read() as u32 - } - - /// Read mcycle and mcycleh registers. - pub fn mcycle(&self) -> u64 { - read64!(mcycleh::read(), mcycle::read()) - } -} - -/// Opaque minstret register. -pub struct MINSTRET { - _0: (), -} - -impl MINSTRET { - /// Read minstret register. - #[inline] - pub fn minstret_lo(&self) -> u32 { - minstret::read() as u32 - } - - /// Read minstreth register. - #[inline] - pub fn minstret_hi(&self) -> u32 { - minstreth::read() as u32 - } - - /// Read minstret and minstreth registers. - pub fn minstret(&self) -> u64 { - read64!(self.minstret_hi(), self.minstret_lo()) - } -} - -/// Opaque mtimer interrupt handling. -pub struct MTIMER { - _0: (), -} - -impl MTIMER { - /// Enable Machine-Timer interrupt. - pub fn enable(&mut self) { - unsafe { mie::set_mtimer() }; - } - - /// Disable Machine-Timer interrupt. - pub fn disable(&mut self) { - unsafe { mie::clear_mtimer(); } - } - - /// Check if the Machine-Timer is interrupt pending. - pub fn is_pending(&self) -> bool { - mip::read().mtimer() - } -} - -/// Parts of CLINT peripheral for fine grained permission control. -pub struct ClintParts { +/// Core-Local Interruptor abstraction +pub struct Clint { + /// Opaque msip register + pub msip: MSIP, /// Opaque mtimecmp register pub mtimecmp: MTIMECMP, /// Opaque mtime register pub mtime: MTIME, - /// Opaque mcycle register - pub mcycle: MCYCLE, - /// Opaque minstret register - pub minstret: MINSTRET, - /// Opaque mtimer register - pub mtimer: MTIMER, } -impl ClintExt for CLINT { - type Parts = ClintParts; - - fn split(self) -> ClintParts { - ClintParts { +impl From for Clint { + fn from(_: CLINT) -> Self { + Clint { + msip: MSIP { _0: () }, mtimecmp: MTIMECMP { _0: () }, - mtime: MTIME, - mcycle: MCYCLE { _0: () }, - minstret: MINSTRET { _0: () }, - mtimer: MTIMER { _0: () }, + mtime: MTIME } } } diff --git a/src/clock.rs b/src/clock.rs index cfc1faf..97864cb 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,7 +1,8 @@ //! Clock configuration use e310x::{PRCI, AONCLK}; -use crate::clint::{MCYCLE, MTIME}; +use crate::clint::MTIME; use riscv::interrupt; +use riscv::register::mcycle; use crate::time::Hertz; @@ -385,19 +386,19 @@ impl Clocks { } /// Measure the coreclk frequency by counting the number of aonclk ticks. - fn _measure_coreclk(&self, min_ticks: u64, mcycle: &MCYCLE) -> Hertz { + fn _measure_coreclk(&self, min_ticks: u64) -> Hertz { let mtime = MTIME; interrupt::free(|_| { // Don't start measuring until we see an mtime tick while mtime.mtime() == mtime.mtime() {} - let start_cycle = mcycle.mcycle(); + let start_cycle = mcycle::read64(); let start_time = mtime.mtime(); // Wait for min_ticks to pass while start_time + min_ticks > mtime.mtime() {} - let end_cycle = mcycle.mcycle(); + let end_cycle = mcycle::read64(); let end_time = mtime.mtime(); let delta_cycle: u64 = end_cycle - start_cycle; @@ -411,10 +412,10 @@ impl Clocks { } /// Measure the coreclk frequency by counting the number of aonclk ticks. - pub fn measure_coreclk(&self, mcycle: &MCYCLE) -> Hertz { + pub fn measure_coreclk(&self) -> Hertz { // warm up I$ - self._measure_coreclk(1, mcycle); + self._measure_coreclk(1); // measure for real - self._measure_coreclk(10, mcycle) + self._measure_coreclk(10) } } diff --git a/src/prelude.rs b/src/prelude.rs index c75c57a..b3912c1 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,7 +7,6 @@ pub use embedded_hal::digital::v2::{ StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, }; -pub use crate::clint::ClintExt as _e310x_hal_clint_ClintExt; pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; From 389e35b5d3e1c01cd146b860fef72a57404bea0e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 00:38:13 +0300 Subject: [PATCH 147/315] Move CLINT driver to core module --- .gitignore | 1 - src/clock.rs | 2 +- src/{ => core}/clint.rs | 0 src/core/counters.rs | 70 +++++++++++++++++++++++++++++++++++++++++ src/core/mod.rs | 13 ++++++++ src/delay.rs | 2 +- src/lib.rs | 2 +- 7 files changed, 86 insertions(+), 4 deletions(-) rename src/{ => core}/clint.rs (100%) create mode 100644 src/core/counters.rs create mode 100644 src/core/mod.rs diff --git a/.gitignore b/.gitignore index becb52e..a9a12f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ Cargo.lock target/ -core .gdb_history \ No newline at end of file diff --git a/src/clock.rs b/src/clock.rs index 97864cb..792bac4 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,6 +1,6 @@ //! Clock configuration use e310x::{PRCI, AONCLK}; -use crate::clint::MTIME; +use crate::core::clint::MTIME; use riscv::interrupt; use riscv::register::mcycle; use crate::time::Hertz; diff --git a/src/clint.rs b/src/core/clint.rs similarity index 100% rename from src/clint.rs rename to src/core/clint.rs diff --git a/src/core/counters.rs b/src/core/counters.rs new file mode 100644 index 0000000..d45137e --- /dev/null +++ b/src/core/counters.rs @@ -0,0 +1,70 @@ +//! Performance counters + +use riscv::register::{mcycle, minstret, mhpmcounter3, mhpmcounter4}; + +/// Opaque mcycle register +pub struct MCYCLE; + +impl MCYCLE { + /// Read mcycle and mcycleh registers. + #[inline] + pub fn value(&self) -> u64 { + mcycle::read64() + } +} + +/// Opaque minstret register. +pub struct MINSTRET; + +impl MINSTRET { + /// Read minstret and minstreth registers. + #[inline] + pub fn value(&self) -> u64 { + minstret::read64() + } +} + +/// Opaque mhpmcounter3 register. +pub struct MHPMCOUNTER3; + +impl MHPMCOUNTER3 { + /// Read mhpmcounter3 and mhpmcounter3h registers. + #[inline] + pub fn value(&self) -> u64 { + mhpmcounter3::read64() + } +} + +/// Opaque mhpmcounter4 register. +pub struct MHPMCOUNTER4; + +impl MHPMCOUNTER4 { + /// Read mhpmcounter4 and mhpmcounter4h registers. + #[inline] + pub fn value(&self) -> u64 { + mhpmcounter4::read64() + } +} + +/// Performance counters +pub struct PerformanceCounters { + /// 64-bit mcycle counter + pub mcycle: MCYCLE, + /// 64-bit minstret counter + pub minstret: MINSTRET, + /// 40-bit mhpmcounter3 counter + pub mhpmcounter3: MHPMCOUNTER3, + /// 40-bit mhpmcounter4 counter + pub mhpmcounter4: MHPMCOUNTER4, +} + +impl PerformanceCounters { + pub(crate) fn new() -> Self { + Self { + mcycle: MCYCLE, + minstret: MINSTRET, + mhpmcounter3: MHPMCOUNTER3, + mhpmcounter4: MHPMCOUNTER4 + } + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..bea997a --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,13 @@ +//! E31 core peripherals + +pub mod clint; +pub mod counters; + +/// Core peripherals +pub struct CorePeripherals { + /// Core-Local Interruptor + pub clint: clint::Clint, + + /// Performance counters + pub counters: counters::PerformanceCounters, +} diff --git a/src/delay.rs b/src/delay.rs index 881b201..53b682b 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,7 +1,7 @@ //! # Delays use embedded_hal::blocking::delay::DelayMs; -use crate::clint::{MTIME, MTIMECMP}; +use crate::core::clint::{MTIME, MTIMECMP}; use crate::clock::Clocks; use riscv::register::{mie, mip}; diff --git a/src/lib.rs b/src/lib.rs index bd058d9..75854ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ pub use e310x; -pub mod clint; +pub mod core; pub mod clock; pub mod delay; pub mod gpio; From 6eede54aa052f23b469728fec0f73f901ad36459 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 00:42:12 +0300 Subject: [PATCH 148/315] Move PLIC driver to core --- src/core/mod.rs | 4 ++++ src/{ => core}/plic.rs | 2 +- src/lib.rs | 1 - src/prelude.rs | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) rename src/{ => core}/plic.rs (99%) diff --git a/src/core/mod.rs b/src/core/mod.rs index bea997a..36f61c6 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -2,12 +2,16 @@ pub mod clint; pub mod counters; +pub mod plic; /// Core peripherals pub struct CorePeripherals { /// Core-Local Interruptor pub clint: clint::Clint, + /// Platform-Level Interrupt Controller + pub plic: plic::PlicParts, + /// Performance counters pub counters: counters::PerformanceCounters, } diff --git a/src/plic.rs b/src/core/plic.rs similarity index 99% rename from src/plic.rs rename to src/core/plic.rs index e1fb067..945f04f 100644 --- a/src/plic.rs +++ b/src/core/plic.rs @@ -1,4 +1,4 @@ -//! Plic +//! Platform-Level Interrupt Controller use core::marker::PhantomData; use riscv::register::{mie, mip}; use riscv::interrupt::Nr; diff --git a/src/lib.rs b/src/lib.rs index 75854ad..cb2f3f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,6 @@ pub mod clock; pub mod delay; pub mod gpio; pub mod device; -pub mod plic; pub mod prelude; pub mod rtc; pub mod serial; diff --git a/src/prelude.rs b/src/prelude.rs index b3912c1..237dcdc 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,7 +10,7 @@ pub use embedded_hal::digital::v2::{ pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; -pub use crate::plic::PlicExt as _e310x_hal_plic_PlicExt; +pub use crate::core::plic::PlicExt as _e310x_hal_plic_PlicExt; pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; From 6ce3a001fe1283f885245b3845454ec407f05f9d Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 00:45:43 +0300 Subject: [PATCH 149/315] Leave TODO --- src/core/counters.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/counters.rs b/src/core/counters.rs index d45137e..bc98508 100644 --- a/src/core/counters.rs +++ b/src/core/counters.rs @@ -56,6 +56,8 @@ pub struct PerformanceCounters { pub mhpmcounter3: MHPMCOUNTER3, /// 40-bit mhpmcounter4 counter pub mhpmcounter4: MHPMCOUNTER4, + + // TODO: mhpmevent3, mhpmevent4 } impl PerformanceCounters { From f638b9cd15647e82f26beddc057f6fd27117fca0 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 00:55:10 +0300 Subject: [PATCH 150/315] Separate core and device peripherals --- src/core/mod.rs | 17 +++++++++++++++++ src/device.rs | 15 +++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/core/mod.rs b/src/core/mod.rs index 36f61c6..b34cb51 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -15,3 +15,20 @@ pub struct CorePeripherals { /// Performance counters pub counters: counters::PerformanceCounters, } + +impl CorePeripherals { + pub(crate) fn new(clint: e310x::CLINT, plic: e310x::PLIC) -> Self { + use plic::PlicExt; + Self { + clint: clint.into(), + plic: plic.split(), + counters: counters::PerformanceCounters::new() + } + } + + /// Steal the peripherals + pub unsafe fn steal() -> Self { + let p = e310x::Peripherals::steal(); + Self::new(p.CLINT, p.PLIC) + } +} diff --git a/src/device.rs b/src/device.rs index c10fe1b..a95d4cf 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,9 +1,10 @@ //! Device resources available in FE310-G000 and FE310-G002 chip packages +use crate::core::CorePeripherals; use crate::gpio::{gpio0::*, GpioExt, Unknown}; use e310x::{ - Peripherals, AONCLK, BACKUP, CLINT, GPIO0, OTP, PLIC, PMU, PRCI, PWM0, PWM1, PWM2, QSPI0, - QSPI1, RTC, UART0, WDOG, + Peripherals, AONCLK, BACKUP, GPIO0, OTP, PMU, PRCI, PWM0, PWM1, PWM2, QSPI0, QSPI1, RTC, UART0, + WDOG, }; #[cfg(feature = "g002")] use e310x::{I2C0, UART1}; @@ -11,10 +12,6 @@ use e310x::{I2C0, UART1}; /// Device peripherals available in a 48QFN package, except GPIO0 #[allow(non_snake_case)] pub struct DevicePeripherals { - /// CLINT peripheral - pub CLINT: CLINT, - /// PLIC peripheral - pub PLIC: PLIC, /// WDOG peripheral pub WDOG: WDOG, /// RTC peripheral @@ -124,6 +121,9 @@ impl From for DeviceGpioPins { /// Device resources available in a 48QFN package pub struct DeviceResources { + /// Core peripherals + pub core_peripherals: CorePeripherals, + /// Device peripherals pub peripherals: DevicePeripherals, @@ -134,8 +134,6 @@ pub struct DeviceResources { impl From for DeviceResources { fn from(p: Peripherals) -> Self { let peripherals = DevicePeripherals { - CLINT: p.CLINT, - PLIC: p.PLIC, WDOG: p.WDOG, RTC: p.RTC, AONCLK: p.AONCLK, @@ -160,6 +158,7 @@ impl From for DeviceResources { }; DeviceResources { + core_peripherals: CorePeripherals::new(p.CLINT, p.PLIC), peripherals, pins: p.GPIO0.into(), } From e4960a955982801a4cb8f22ffad58b8178efa9c8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 01:09:01 +0300 Subject: [PATCH 151/315] Do not rely on initial clock tree settings Configure internal oscillator first. Closes #16 --- src/clock.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 792bac4..42b6ad9 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -75,10 +75,19 @@ impl CoreClk { pub(crate) fn freeze(self) -> Hertz { // Assume `psdclkbypass_n` is not used + // Temporarily switch to the internal oscillator + let prci = unsafe { &*PRCI::ptr() }; + let hfrosc_freq = self.configure_hfrosc(); + // Switch to HFROSC, bypass PLL + prci.pllcfg.modify(|_, w| w + .sel().bit(false) + .bypass().bit(true) + ); + if let Some(freq) = self.hfxosc { self.configure_with_external(freq) } else { - self.configure_with_internal() + self.configure_with_internal(hfrosc_freq) } } @@ -122,11 +131,9 @@ impl CoreClk { } /// Configures clock generation system with internal oscillator - fn configure_with_internal(self) -> Hertz { + fn configure_with_internal(self, hfrosc_freq: Hertz) -> Hertz { let prci = unsafe { &*PRCI::ptr() }; - let hfrosc_freq = self.configure_hfrosc(); - let freq; if hfrosc_freq.0 == self.coreclk.0 { // Use internal oscillator with bypassed PLL From 8c0499390b5662b5ce269c79437b52c236d0ea4f Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 01:24:33 +0300 Subject: [PATCH 152/315] Remove PlicExt, do not disable interrupts upon initialization --- src/core/mod.rs | 5 ++--- src/core/plic.rs | 21 +++++---------------- src/prelude.rs | 1 - 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/core/mod.rs b/src/core/mod.rs index b34cb51..9fc06bb 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -10,7 +10,7 @@ pub struct CorePeripherals { pub clint: clint::Clint, /// Platform-Level Interrupt Controller - pub plic: plic::PlicParts, + pub plic: plic::Plic, /// Performance counters pub counters: counters::PerformanceCounters, @@ -18,10 +18,9 @@ pub struct CorePeripherals { impl CorePeripherals { pub(crate) fn new(clint: e310x::CLINT, plic: e310x::PLIC) -> Self { - use plic::PlicExt; Self { clint: clint.into(), - plic: plic.split(), + plic: plic.into(), counters: counters::PerformanceCounters::new() } } diff --git a/src/core/plic.rs b/src/core/plic.rs index 945f04f..ae1a8bf 100644 --- a/src/core/plic.rs +++ b/src/core/plic.rs @@ -68,14 +68,8 @@ pub struct IrqRtc; /// Uart0 interrupt (type state) pub struct IrqUart0; -/// PlicExt trait extends `PLIC` peripheral. -pub trait PlicExt { - /// Splits the `PLIC` peripheral into parts. - fn split(self) -> PlicParts; -} - /// Parts of `PLIC` peripheral for fine grained permissions. -pub struct PlicParts { +pub struct Plic { /// Opaque mext register pub mext: MEXT, /// Opaque threshold register @@ -90,15 +84,9 @@ pub struct PlicParts { pub uart0: INTERRUPT, } -impl PlicExt for PLIC { - fn split(self) -> PlicParts { - // Disable all interrupts by default - unsafe { - self.enable[0].write(|w| w.bits(0)); - self.enable[1].write(|w| w.bits(0)); - } - - PlicParts { +impl From for Plic { + fn from(_: PLIC) -> Self { + Plic { mext: MEXT { _0: () }, threshold: THRESHOLD { _0: () }, claim: CLAIM { _0: () }, @@ -124,6 +112,7 @@ impl PlicExt for PLIC { } } + /// Opaque MEXT register. pub struct MEXT { _0: (), diff --git a/src/prelude.rs b/src/prelude.rs index 237dcdc..db42b0a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,7 +10,6 @@ pub use embedded_hal::digital::v2::{ pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; -pub use crate::core::plic::PlicExt as _e310x_hal_plic_PlicExt; pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; From 8628649c2bb17c7be25ab26c9ccd9f357fe66817 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 3 Jul 2019 01:28:30 +0300 Subject: [PATCH 153/315] Remove mhpmcounters (not present in riscv yet) --- src/core/counters.rs | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/src/core/counters.rs b/src/core/counters.rs index bc98508..f461b63 100644 --- a/src/core/counters.rs +++ b/src/core/counters.rs @@ -1,6 +1,6 @@ //! Performance counters -use riscv::register::{mcycle, minstret, mhpmcounter3, mhpmcounter4}; +use riscv::register::{mcycle, minstret}; /// Opaque mcycle register pub struct MCYCLE; @@ -24,27 +24,6 @@ impl MINSTRET { } } -/// Opaque mhpmcounter3 register. -pub struct MHPMCOUNTER3; - -impl MHPMCOUNTER3 { - /// Read mhpmcounter3 and mhpmcounter3h registers. - #[inline] - pub fn value(&self) -> u64 { - mhpmcounter3::read64() - } -} - -/// Opaque mhpmcounter4 register. -pub struct MHPMCOUNTER4; - -impl MHPMCOUNTER4 { - /// Read mhpmcounter4 and mhpmcounter4h registers. - #[inline] - pub fn value(&self) -> u64 { - mhpmcounter4::read64() - } -} /// Performance counters pub struct PerformanceCounters { @@ -52,11 +31,8 @@ pub struct PerformanceCounters { pub mcycle: MCYCLE, /// 64-bit minstret counter pub minstret: MINSTRET, - /// 40-bit mhpmcounter3 counter - pub mhpmcounter3: MHPMCOUNTER3, - /// 40-bit mhpmcounter4 counter - pub mhpmcounter4: MHPMCOUNTER4, + // TODO: mhpmcounter3, mhpmcounter4 // TODO: mhpmevent3, mhpmevent4 } @@ -65,8 +41,6 @@ impl PerformanceCounters { Self { mcycle: MCYCLE, minstret: MINSTRET, - mhpmcounter3: MHPMCOUNTER3, - mhpmcounter4: MHPMCOUNTER4 } } } From 1a07791df6d6210b59315a25d7a228e9451b6d80 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 5 Jul 2019 16:00:15 +0300 Subject: [PATCH 154/315] Bump version (0.7.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b20f64c..e1cbdc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.6.1" +version = "0.7.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 7f01c37d86b82bde1179683f692f59beb4b0af9c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 5 Jul 2019 17:54:19 +0300 Subject: [PATCH 155/315] Update e310x-hal dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4ead38f..7f61680 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.6.0" +e310x-hal = "0.7.0" embedded-hal = "0.2.3" riscv = "0.5.2" nb = "0.1.2" From f60ffeb071bd906d9abbb9720816b0a13398003b Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 5 Jul 2019 18:43:53 +0300 Subject: [PATCH 156/315] Implement BoardResources --- src/board.rs | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ 2 files changed, 130 insertions(+) create mode 100644 src/board.rs diff --git a/src/board.rs b/src/board.rs new file mode 100644 index 0000000..3db7bd9 --- /dev/null +++ b/src/board.rs @@ -0,0 +1,127 @@ +//! Board resources + +use e310x_hal::gpio::{Unknown, gpio0::*}; +use e310x_hal::device::{DevicePeripherals, DeviceResources, DeviceGpioPins}; +use e310x_hal::core::CorePeripherals; + +/// Pins exposed on the Arduino connector +pub struct BoardPins { + /// DIG0 / UART_RX + pub dig0: Pin16, + + /// DIG1 / UART_TX + pub dig1: Pin17, + + /// DIG2 + pub dig2: Pin18, + + /// DIG3 / PWM + pub dig3: Pin19, + + /// DIG4 + pub dig4: Pin20, + + /// DIG5 / PWM + pub dig5: Pin21, + + /// DIG6 / PWM + pub dig6: Pin22, + + /// DIG7 + pub dig7: Pin23, + + /// DIG8 + pub dig8: Pin0, + + /// DIG9 / PWM + pub dig9: Pin1, + + /// DIG10 / SS / PWM + pub dig10: Pin2, + + /// DIG11 / MOSI / PWM + pub dig11: Pin3, + + /// DIG12 / MISO + pub dig12: Pin4, + + /// DIG13 / SCK + pub dig13: Pin5, + + /// DIG15 + pub dig15: Pin9, + + /// DIG16 + pub dig16: Pin10, + + /// DIG17 + pub dig17: Pin11, + + /// DIG18 / SDA (RevB) + pub dig18: Pin12, + + /// DIG19 / SCL (RevB) + pub dig19: Pin13, +} + +impl From for BoardPins { + fn from(pins: DeviceGpioPins) -> Self { + BoardPins { + dig0: pins.pin16, + dig1: pins.pin17, + dig2: pins.pin18, + dig3: pins.pin19, + dig4: pins.pin20, + dig5: pins.pin21, + dig6: pins.pin22, + dig7: pins.pin23, + dig8: pins.pin0, + dig9: pins.pin1, + dig10: pins.pin2, + dig11: pins.pin3, + dig12: pins.pin4, + dig13: pins.pin5, + dig15: pins.pin9, + dig16: pins.pin10, + dig17: pins.pin11, + dig18: pins.pin12, + dig19: pins.pin13, + } + } +} + + +/// Board resources +pub struct BoardResources { + /// Core peripherals + pub core_peripherals: CorePeripherals, + + /// Device peripherals + pub peripherals: DevicePeripherals, + + /// Board pins + pub pins: BoardPins, +} + +impl From for BoardResources { + fn from(r: DeviceResources) -> Self { + BoardResources { + core_peripherals: r.core_peripherals, + peripherals: r.peripherals, + pins: r.pins.into() + } + } +} + +impl BoardResources { + /// Returns all the board resources *once* + #[inline] + pub fn take() -> Option { + DeviceResources::take().map(BoardResources::from) + } + + /// Unchecked version of `BoardResources::take` + pub unsafe fn steal() -> Self { + DeviceResources::steal().into() + } +} diff --git a/src/lib.rs b/src/lib.rs index 5d9b14d..16c74cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,5 +13,8 @@ pub mod led; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub use led::{RED, GREEN, BLUE, rgb, Led}; +pub mod board; +pub use board::BoardResources; + pub mod stdout; pub use stdout::configure as configure_stdout; From fce90b99f6e4ade1deb29825091568e3f6e552c4 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 5 Jul 2019 18:48:42 +0300 Subject: [PATCH 157/315] Bump version (0.7.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7f61680..eecdaee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.6.0" +version = "0.7.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 6a5ae8dabb5599dccdac608fef329ba75e391e9d Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 5 Jul 2019 19:42:47 +0300 Subject: [PATCH 158/315] Replace char literal with byte --- src/stdout.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stdout.rs b/src/stdout.rs index 43ad49c..57785fb 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -14,8 +14,8 @@ impl<'p, T> Write for Stdout<'p, T> { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { - if *byte == '\n' as u8 { - let res = block!(self.0.write('\r' as u8)); + if *byte == b'\n' { + let res = block!(self.0.write(b'\r')); if res.is_err() { return Err(::core::fmt::Error); From 4f998b62e36f4e6cf8bdd684c0db77c75867137e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 8 Jul 2019 01:38:35 +0300 Subject: [PATCH 159/315] [WIP] Assert CS for the whole packet --- src/spi.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 5a3b1ff..13d1bc5 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -272,13 +272,20 @@ impl embedded_hal::blocking::spi::Write for Spi type Error = Infallible; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - // Save watermark levels + // Save watermark levels and csmode let txmark = self.spi.txmark.read().value().bits(); let rxmark = self.spi.rxmark.read().value().bits(); + let csmode = self.spi.csmode.read().bits(); + let new_csmode = if csmode == 3 { + 3 // Disable hardware control of the CS pin + } else { + 2 // Keep CS continuously asserted after the initial frame + }; - // Set watermark levels + // Set watermark levels and csmode self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + self.spi.csmode.write(|w| unsafe { w.bits(new_csmode) }); // Ensure that RX FIFO is empty while self.spi.ip.read().rxwm().bit_is_set() { @@ -300,9 +307,10 @@ impl embedded_hal::blocking::spi::Write for Spi } } - // Restore watermark levels + // Restore watermark levels and csmode self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); + self.spi.csmode.write(|w| unsafe { w.bits(csmode) }); Ok(()) } From 08197c5f5b8bb8f813e7132db9a478d1bd54a178 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 8 Jul 2019 10:48:19 -0600 Subject: [PATCH 160/315] add pin! and pins! macros for easy pin selection --- Cargo.toml | 2 +- src/gpio.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/gpio.rs diff --git a/Cargo.toml b/Cargo.toml index eecdaee..a45230a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.7.0" +version = "0.7.1" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..519c6d1 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,88 @@ +//! GPIO Pin mapping macros crate + +/// +/// Hifive1 PIN mappings (alias -> GPIO.pinX) +/// +#[macro_export] +macro_rules! pin_name { + // empty + ($gpio:ident, none) => { () }; + // spi + ($gpio:ident, spi_sck) => { $gpio.pin5 }; + ($gpio:ident, spi_mosi) => { $gpio.pin3 }; + ($gpio:ident, spi_miso) => { $gpio.pin4 }; + ($gpio:ident, spi_ss0) => { $gpio.pin2 }; + // spi_ss1 is not documented + ($gpio:ident, spi_ss2) => { $gpio.pin9 }; + ($gpio:ident, spi_cs3) => { $gpio.pin10 }; + // i2c + ($gpio:ident, i2c_sda) => { $gpio.pin12 }; + ($gpio:ident, i2c_scl) => { $gpio.pin13 }; + // serial + ($gpio:ident, serial_tx) => { $gpio.pin17 }; + ($gpio:ident, serial_rx) => { $gpio.pin16 }; + // digital/physical + ($gpio:ident, dig0) => { $gpio.pin16 }; + ($gpio:ident, dig1) => { $gpio.pin17 }; + ($gpio:ident, dig2) => { $gpio.pin18 }; + ($gpio:ident, dig3) => { $gpio.pin19 }; + ($gpio:ident, dig4) => { $gpio.pin20 }; + ($gpio:ident, dig5) => { $gpio.pin21 }; + ($gpio:ident, dig6) => { $gpio.pin22 }; + ($gpio:ident, dig7) => { $gpio.pin23 }; + ($gpio:ident, dig8) => { $gpio.pin0 }; + ($gpio:ident, dig9) => { $gpio.pin1 }; + ($gpio:ident, dig10) => { $gpio.pin2 }; + ($gpio:ident, dig11) => { $gpio.pin3 }; + ($gpio:ident, dig12) => { $gpio.pin4 }; + ($gpio:ident, dig13) => { $gpio.pin5 }; + ($gpio:ident, dig14) => { $gpio.pin8 }; // tested + ($gpio:ident, dig15) => { $gpio.pin9 }; + ($gpio:ident, dig16) => { $gpio.pin10 }; + ($gpio:ident, dig17) => { $gpio.pin11 }; + ($gpio:ident, dig18) => { $gpio.pin12 }; + ($gpio:ident, dig19) => { $gpio.pin13 }; +} + +/// +/// Returns single pin for given gpio object mapped accordingly +/// +/// *mappings* +/// +/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) +/// - i2c_ -- I2C pins where is one of (sda, scl) +/// - serial_ -- Serial pins where is one of (tx, rx) +/// - dig# -- Digital/physical pins on the board where # is from range <0..19> +/// +/// *example* +/// +/// `pin!(gpio.spi_mosi) -> gpio.pin3` +/// +#[macro_export] +macro_rules! pin { + ($gpio:ident.$name:ident) => { + $crate::pin_name!($gpio, $name) + } +} + +/// +/// Returns tuple of pins for given gpio object mapped accordingly +/// +/// *mappings* +/// +/// - none -- Returns () for empty pin if needed in tuple +/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) +/// - i2c_ -- I2C pins where is one of (sda, scl) +/// - serial_ -- Serial pins where is one of (tx, rx) +/// - dig# -- Digital/physical pins on the board where # is from range <0..19> +/// +/// *example* +/// +/// `pin!(gpio.spi_mosi) -> gpio.pin3` +/// +#[macro_export] +macro_rules! pins { + ( $gpio:ident, ($($name:ident),+) ) => { + ($($crate::pin_name!($gpio, $name)),+) + } +} diff --git a/src/lib.rs b/src/lib.rs index 16c74cc..a3b78b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,5 @@ pub use board::BoardResources; pub mod stdout; pub use stdout::configure as configure_stdout; + +pub mod gpio; \ No newline at end of file From fef5ff7b016abbaffcf1567fd88a7f06b0a66152 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Jul 2019 00:08:14 +0300 Subject: [PATCH 161/315] Hide gpio from docs --- src/gpio.rs | 1 + src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gpio.rs b/src/gpio.rs index 519c6d1..7f3cfb3 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -4,6 +4,7 @@ /// Hifive1 PIN mappings (alias -> GPIO.pinX) /// #[macro_export] +#[doc(hidden)] macro_rules! pin_name { // empty ($gpio:ident, none) => { () }; diff --git a/src/lib.rs b/src/lib.rs index a3b78b1..b2f7923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,4 +19,5 @@ pub use board::BoardResources; pub mod stdout; pub use stdout::configure as configure_stdout; -pub mod gpio; \ No newline at end of file +#[doc(hidden)] +pub mod gpio; From 3a41801aeaaeadb2d382aa14c8176cff5cbfcfeb Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Jul 2019 00:17:11 +0300 Subject: [PATCH 162/315] Fix docs --- src/gpio.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 7f3cfb3..06abdff 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,7 +1,5 @@ -//! GPIO Pin mapping macros crate - /// -/// Hifive1 PIN mappings (alias -> GPIO.pinX) +/// HiFive1 PIN mappings (alias -> GPIO.pinX) /// #[macro_export] #[doc(hidden)] @@ -79,7 +77,7 @@ macro_rules! pin { /// /// *example* /// -/// `pin!(gpio.spi_mosi) -> gpio.pin3` +/// `pins!(gpio, (spi_mosi, spi_miso, spi_sck, spi_ss0)) -> (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2)` /// #[macro_export] macro_rules! pins { From 2bd511726c03e808e204863cc44c836db0c6b876 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 8 Jul 2019 15:18:28 -0600 Subject: [PATCH 163/315] use pin directly with comma separator --- src/gpio.rs | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 06abdff..ca14de4 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,9 +1,19 @@ /// -/// HiFive1 PIN mappings (alias -> GPIO.pinX) +/// Returns single pin for given gpio object mapped accordingly +/// +/// *mappings* +/// +/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) +/// - i2c_ -- I2C pins where is one of (sda, scl) +/// - serial_ -- Serial pins where is one of (tx, rx) +/// - dig# -- Digital/physical pins on the board where # is from range <0..19> +/// +/// *example* +/// +/// `pin!(gpio.spi_mosi) -> gpio.pin3` /// #[macro_export] -#[doc(hidden)] -macro_rules! pin_name { +macro_rules! pin { // empty ($gpio:ident, none) => { () }; // spi @@ -43,27 +53,6 @@ macro_rules! pin_name { ($gpio:ident, dig19) => { $gpio.pin13 }; } -/// -/// Returns single pin for given gpio object mapped accordingly -/// -/// *mappings* -/// -/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) -/// - i2c_ -- I2C pins where is one of (sda, scl) -/// - serial_ -- Serial pins where is one of (tx, rx) -/// - dig# -- Digital/physical pins on the board where # is from range <0..19> -/// -/// *example* -/// -/// `pin!(gpio.spi_mosi) -> gpio.pin3` -/// -#[macro_export] -macro_rules! pin { - ($gpio:ident.$name:ident) => { - $crate::pin_name!($gpio, $name) - } -} - /// /// Returns tuple of pins for given gpio object mapped accordingly /// From 1e3c3054fded4749157d898df599b82efe70b18c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Jul 2019 00:28:15 +0300 Subject: [PATCH 164/315] Improve formatting --- src/gpio.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index ca14de4..835c354 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,16 +1,18 @@ /// /// Returns single pin for given gpio object mapped accordingly /// -/// *mappings* +/// # Mappings /// -/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) -/// - i2c_ -- I2C pins where is one of (sda, scl) -/// - serial_ -- Serial pins where is one of (tx, rx) -/// - dig# -- Digital/physical pins on the board where # is from range <0..19> +/// - `spi_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) +/// - `i2c_` — I2C pins where `` is one of (`sda`, `scl`) +/// - `serial_` — Serial pins where is one of (`tx`, `rx`) +/// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// -/// *example* +/// # Example /// -/// `pin!(gpio.spi_mosi) -> gpio.pin3` +/// ``` +/// let mosi = pin!(gpio, spi_mosi); // gpio.pin3 +/// ``` /// #[macro_export] macro_rules! pin { @@ -56,17 +58,20 @@ macro_rules! pin { /// /// Returns tuple of pins for given gpio object mapped accordingly /// -/// *mappings* +/// # Mappings /// -/// - none -- Returns () for empty pin if needed in tuple -/// - spi_ -- SPI pins where is one of (sck, mosi, miso, ss0, ss2, ss3) -/// - i2c_ -- I2C pins where is one of (sda, scl) -/// - serial_ -- Serial pins where is one of (tx, rx) -/// - dig# -- Digital/physical pins on the board where # is from range <0..19> +/// - `none` — Returns `()` for empty pin if needed in tuple +/// - `spi_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) +/// - `i2c_` — I2C pins where `` is one of (`sda`, `scl`) +/// - `serial_` — Serial pins where is one of (`tx`, `rx`) +/// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// -/// *example* +/// # Example /// -/// `pins!(gpio, (spi_mosi, spi_miso, spi_sck, spi_ss0)) -> (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2)` +/// ``` +/// let (mosi, miso, sck, cs) = pins!(gpio, (spi_mosi, spi_miso, spi_sck, spi_ss0)); +/// // (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2) +/// ``` /// #[macro_export] macro_rules! pins { From 6b5c354c6a63fdc0955324a4ea01c69dfaa28d45 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 8 Jul 2019 15:33:14 -0600 Subject: [PATCH 165/315] serial -> uart, add numbering to spi and i2c --- src/gpio.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 835c354..121a4a3 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -3,15 +3,15 @@ /// /// # Mappings /// -/// - `spi_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) -/// - `i2c_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `serial_` — Serial pins where is one of (`tx`, `rx`) +/// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) +/// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) +/// - `uart0_` — Serial pins where is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// /// # Example /// /// ``` -/// let mosi = pin!(gpio, spi_mosi); // gpio.pin3 +/// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 /// ``` /// #[macro_export] @@ -19,19 +19,19 @@ macro_rules! pin { // empty ($gpio:ident, none) => { () }; // spi - ($gpio:ident, spi_sck) => { $gpio.pin5 }; - ($gpio:ident, spi_mosi) => { $gpio.pin3 }; - ($gpio:ident, spi_miso) => { $gpio.pin4 }; - ($gpio:ident, spi_ss0) => { $gpio.pin2 }; + ($gpio:ident, spi0_sck) => { $gpio.pin5 }; + ($gpio:ident, spi0_mosi) => { $gpio.pin3 }; + ($gpio:ident, spi0_miso) => { $gpio.pin4 }; + ($gpio:ident, spi0_ss0) => { $gpio.pin2 }; // spi_ss1 is not documented - ($gpio:ident, spi_ss2) => { $gpio.pin9 }; - ($gpio:ident, spi_cs3) => { $gpio.pin10 }; + ($gpio:ident, spi0_ss2) => { $gpio.pin9 }; + ($gpio:ident, spi0_cs3) => { $gpio.pin10 }; // i2c - ($gpio:ident, i2c_sda) => { $gpio.pin12 }; - ($gpio:ident, i2c_scl) => { $gpio.pin13 }; + ($gpio:ident, i2c0_sda) => { $gpio.pin12 }; + ($gpio:ident, i2c0_scl) => { $gpio.pin13 }; // serial - ($gpio:ident, serial_tx) => { $gpio.pin17 }; - ($gpio:ident, serial_rx) => { $gpio.pin16 }; + ($gpio:ident, uart0_tx) => { $gpio.pin17 }; + ($gpio:ident, uart0_rx) => { $gpio.pin16 }; // digital/physical ($gpio:ident, dig0) => { $gpio.pin16 }; ($gpio:ident, dig1) => { $gpio.pin17 }; @@ -61,15 +61,15 @@ macro_rules! pin { /// # Mappings /// /// - `none` — Returns `()` for empty pin if needed in tuple -/// - `spi_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) -/// - `i2c_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `serial_` — Serial pins where is one of (`tx`, `rx`) +/// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) +/// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) +/// - `uart0_` — Serial pins where is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// /// # Example /// /// ``` -/// let (mosi, miso, sck, cs) = pins!(gpio, (spi_mosi, spi_miso, spi_sck, spi_ss0)); +/// let (mosi, miso, sck, cs) = pins!(gpio, (spi0_mosi, spi0_miso, spi0_sck, spi0_ss0)); /// // (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2) /// ``` /// From f4bdcfb0acff3cba519fc642b8b3e5587846fa29 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 9 Jul 2019 00:35:30 +0300 Subject: [PATCH 166/315] Replace Serial with UART in docs --- src/gpio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 121a4a3..f01f024 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -5,7 +5,7 @@ /// /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `uart0_` — Serial pins where is one of (`tx`, `rx`) +/// - `uart0_` — UART pins where is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// /// # Example @@ -63,7 +63,7 @@ macro_rules! pin { /// - `none` — Returns `()` for empty pin if needed in tuple /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `uart0_` — Serial pins where is one of (`tx`, `rx`) +/// - `uart0_` — UART pins where is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// /// # Example From 73307003644d0ee4964f66c67e1cb9ec374b69a3 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 13 Jul 2019 21:06:14 -0600 Subject: [PATCH 167/315] use DeviceGpioPins directly --- src/board.rs | 90 +--------------------------------------------------- 1 file changed, 1 insertion(+), 89 deletions(-) diff --git a/src/board.rs b/src/board.rs index 3db7bd9..b441cf1 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,96 +1,8 @@ //! Board resources -use e310x_hal::gpio::{Unknown, gpio0::*}; use e310x_hal::device::{DevicePeripherals, DeviceResources, DeviceGpioPins}; use e310x_hal::core::CorePeripherals; -/// Pins exposed on the Arduino connector -pub struct BoardPins { - /// DIG0 / UART_RX - pub dig0: Pin16, - - /// DIG1 / UART_TX - pub dig1: Pin17, - - /// DIG2 - pub dig2: Pin18, - - /// DIG3 / PWM - pub dig3: Pin19, - - /// DIG4 - pub dig4: Pin20, - - /// DIG5 / PWM - pub dig5: Pin21, - - /// DIG6 / PWM - pub dig6: Pin22, - - /// DIG7 - pub dig7: Pin23, - - /// DIG8 - pub dig8: Pin0, - - /// DIG9 / PWM - pub dig9: Pin1, - - /// DIG10 / SS / PWM - pub dig10: Pin2, - - /// DIG11 / MOSI / PWM - pub dig11: Pin3, - - /// DIG12 / MISO - pub dig12: Pin4, - - /// DIG13 / SCK - pub dig13: Pin5, - - /// DIG15 - pub dig15: Pin9, - - /// DIG16 - pub dig16: Pin10, - - /// DIG17 - pub dig17: Pin11, - - /// DIG18 / SDA (RevB) - pub dig18: Pin12, - - /// DIG19 / SCL (RevB) - pub dig19: Pin13, -} - -impl From for BoardPins { - fn from(pins: DeviceGpioPins) -> Self { - BoardPins { - dig0: pins.pin16, - dig1: pins.pin17, - dig2: pins.pin18, - dig3: pins.pin19, - dig4: pins.pin20, - dig5: pins.pin21, - dig6: pins.pin22, - dig7: pins.pin23, - dig8: pins.pin0, - dig9: pins.pin1, - dig10: pins.pin2, - dig11: pins.pin3, - dig12: pins.pin4, - dig13: pins.pin5, - dig15: pins.pin9, - dig16: pins.pin10, - dig17: pins.pin11, - dig18: pins.pin12, - dig19: pins.pin13, - } - } -} - - /// Board resources pub struct BoardResources { /// Core peripherals @@ -100,7 +12,7 @@ pub struct BoardResources { pub peripherals: DevicePeripherals, /// Board pins - pub pins: BoardPins, + pub pins: DeviceGpioPins, } impl From for BoardResources { From 04c2de6ce48532d84ea1918717c480fda18723ce Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 11:01:36 -0600 Subject: [PATCH 168/315] remove BoardResources --- src/board.rs | 39 --------------------------------------- src/lib.rs | 3 --- 2 files changed, 42 deletions(-) delete mode 100644 src/board.rs diff --git a/src/board.rs b/src/board.rs deleted file mode 100644 index b441cf1..0000000 --- a/src/board.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Board resources - -use e310x_hal::device::{DevicePeripherals, DeviceResources, DeviceGpioPins}; -use e310x_hal::core::CorePeripherals; - -/// Board resources -pub struct BoardResources { - /// Core peripherals - pub core_peripherals: CorePeripherals, - - /// Device peripherals - pub peripherals: DevicePeripherals, - - /// Board pins - pub pins: DeviceGpioPins, -} - -impl From for BoardResources { - fn from(r: DeviceResources) -> Self { - BoardResources { - core_peripherals: r.core_peripherals, - peripherals: r.peripherals, - pins: r.pins.into() - } - } -} - -impl BoardResources { - /// Returns all the board resources *once* - #[inline] - pub fn take() -> Option { - DeviceResources::take().map(BoardResources::from) - } - - /// Unchecked version of `BoardResources::take` - pub unsafe fn steal() -> Self { - DeviceResources::steal().into() - } -} diff --git a/src/lib.rs b/src/lib.rs index b2f7923..ea37a19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,9 +13,6 @@ pub mod led; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub use led::{RED, GREEN, BLUE, rgb, Led}; -pub mod board; -pub use board::BoardResources; - pub mod stdout; pub use stdout::configure as configure_stdout; From 70bb47ceb7aa75fbb57c6337678f86e74a72a6ee Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 11:01:43 -0600 Subject: [PATCH 169/315] bump riscv dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a45230a..37f9713 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] e310x-hal = "0.7.0" embedded-hal = "0.2.3" -riscv = "0.5.2" +riscv = "0.5.3" nb = "0.1.2" [features] From 0b6ca1492f2090c7d441e934c548b4f95a3d6a20 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 11:18:32 -0600 Subject: [PATCH 170/315] fix pins! typo + add led_ naming --- src/gpio.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index f01f024..522a018 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -5,8 +5,9 @@ /// /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `uart0_` — UART pins where is one of (`tx`, `rx`) +/// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 +/// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) /// /// # Example /// @@ -53,6 +54,11 @@ macro_rules! pin { ($gpio:ident, dig17) => { $gpio.pin11 }; ($gpio:ident, dig18) => { $gpio.pin12 }; ($gpio:ident, dig19) => { $gpio.pin13 }; + // internal LED + ($gpio:ident, led_red) => { $gpio.pin22 }; + ($gpio:ident, led_green) => { $gpio.pin19 }; + ($gpio:ident, led_blue) => { $gpio.pin21 }; + } /// @@ -63,8 +69,9 @@ macro_rules! pin { /// - `none` — Returns `()` for empty pin if needed in tuple /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) -/// - `uart0_` — UART pins where is one of (`tx`, `rx`) +/// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 +/// - `led_` - Internal LED light pins `` is one of (`red`, `green`, `blue`) /// /// # Example /// @@ -76,6 +83,6 @@ macro_rules! pin { #[macro_export] macro_rules! pins { ( $gpio:ident, ($($name:ident),+) ) => { - ($($crate::pin_name!($gpio, $name)),+) + ($($crate::pin!($gpio, $name)),+) } } From c46f2f3058c984df3aff685637bf23635958b4ab Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 11:27:49 -0600 Subject: [PATCH 171/315] fix cs3 -> ss3 --- src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpio.rs b/src/gpio.rs index 522a018..d4bf258 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -26,7 +26,7 @@ macro_rules! pin { ($gpio:ident, spi0_ss0) => { $gpio.pin2 }; // spi_ss1 is not documented ($gpio:ident, spi0_ss2) => { $gpio.pin9 }; - ($gpio:ident, spi0_cs3) => { $gpio.pin10 }; + ($gpio:ident, spi0_ss3) => { $gpio.pin10 }; // i2c ($gpio:ident, i2c0_sda) => { $gpio.pin12 }; ($gpio:ident, i2c0_scl) => { $gpio.pin13 }; From 89bbef05b34f06ebb37de26184409da3af1486a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Katona?= Date: Tue, 16 Jul 2019 11:24:49 -0600 Subject: [PATCH 172/315] Update src/gpio.rs Co-Authored-By: Vadim Kaushan --- src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpio.rs b/src/gpio.rs index d4bf258..7a3d247 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -54,7 +54,7 @@ macro_rules! pin { ($gpio:ident, dig17) => { $gpio.pin11 }; ($gpio:ident, dig18) => { $gpio.pin12 }; ($gpio:ident, dig19) => { $gpio.pin13 }; - // internal LED + // onboard LEDs ($gpio:ident, led_red) => { $gpio.pin22 }; ($gpio:ident, led_green) => { $gpio.pin19 }; ($gpio:ident, led_blue) => { $gpio.pin21 }; From fa9abb9325d8833df59471449ebfa3c85cb5cd2d Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 12:11:06 -0600 Subject: [PATCH 173/315] update to latest e310x + SPI mode fix --- Cargo.toml | 6 +++--- src/spi.rs | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1cbdc0..8ebb0bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.7.0" +version = "0.8.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -12,8 +12,8 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" -riscv = "0.5.2" -e310x = { version = "0.5.1", features = ["rt"] } +riscv = "0.5.3" +e310x = { version = "0.6.0", features = ["rt"] } [features] g002 = ["e310x/g002"] diff --git a/src/spi.rs b/src/spi.rs index 13d1bc5..0f7eedf 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -122,7 +122,7 @@ impl Spi { let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { spi.csid.write(|w| unsafe { w.bits(cs_index) }); - 0 // AUTO: Assert/de-assert CS at the beginning/end of each frame + 2 // AUTO: Assert/de-assert CS at the beginning/end of each frame } else { 3 // OFF: Disable hardware control of the CS pin }; @@ -196,6 +196,20 @@ impl Spi { self.spi.ie.write(|w| w.rxwm().clear_bit()) } + /// Set AUTO CS mode to per-word operation + pub fn cs_mode_word(&mut self) { + if self.spi.csmode.read().bits() != 3 { + self.spi.csmode.write(|w| unsafe { w.bits(0) }); + } + } + + /// Set AUTO CS mode to per-frame operation + pub fn cs_mode_frame(&mut self) { + if self.spi.csmode.read().bits() != 3 { + self.spi.csmode.write(|w| unsafe { w.bits(2) }); + } + } + /// Releases the SPI peripheral and associated pins pub fn free(self) -> (SPI, PINS) { (self.spi, self.pins) @@ -276,16 +290,11 @@ impl embedded_hal::blocking::spi::Write for Spi let txmark = self.spi.txmark.read().value().bits(); let rxmark = self.spi.rxmark.read().value().bits(); let csmode = self.spi.csmode.read().bits(); - let new_csmode = if csmode == 3 { - 3 // Disable hardware control of the CS pin - } else { - 2 // Keep CS continuously asserted after the initial frame - }; // Set watermark levels and csmode self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); - self.spi.csmode.write(|w| unsafe { w.bits(new_csmode) }); + self.spi.csmode.write(|w| unsafe { w.bits(csmode) }); // Ensure that RX FIFO is empty while self.spi.ip.read().rxwm().bit_is_set() { From d43f1229b15b798583714abb8983250eed533ea9 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 12:13:04 -0600 Subject: [PATCH 174/315] remove unnecessary csmode save/restore --- src/spi.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 0f7eedf..ca11260 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -286,15 +286,13 @@ impl embedded_hal::blocking::spi::Write for Spi type Error = Infallible; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - // Save watermark levels and csmode + // Save watermark levels let txmark = self.spi.txmark.read().value().bits(); let rxmark = self.spi.rxmark.read().value().bits(); - let csmode = self.spi.csmode.read().bits(); - // Set watermark levels and csmode + // Set watermark levels self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); - self.spi.csmode.write(|w| unsafe { w.bits(csmode) }); // Ensure that RX FIFO is empty while self.spi.ip.read().rxwm().bit_is_set() { @@ -316,10 +314,9 @@ impl embedded_hal::blocking::spi::Write for Spi } } - // Restore watermark levels and csmode + // Restore watermark levels self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); - self.spi.csmode.write(|w| unsafe { w.bits(csmode) }); Ok(()) } From 9364f6e62738a2c335a1ce95d0258016fb5ae1cf Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 16 Jul 2019 13:05:31 -0600 Subject: [PATCH 175/315] add doc about AUTO CS mode to new() --- src/spi.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spi.rs b/src/spi.rs index ca11260..ae4728f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -112,6 +112,7 @@ pub struct Spi { impl Spi { /// Configures the SPI peripheral to operate in full duplex master mode + /// Defaults to using AUTO CS in FRAME mode if PINS configuration allows it pub fn new(spi: SPI, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self where PINS: Pins From d0917639cd6d717fe8a8c5b7d53528d29c555949 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 16 Jul 2019 22:49:24 +0300 Subject: [PATCH 176/315] Update e310x-hal dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 37f9713..732bd40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.7.0" +e310x-hal = "0.8.0" embedded-hal = "0.2.3" riscv = "0.5.3" nb = "0.1.2" From 19f59414bdcd1620248af56ff5e71d0c34a1fc79 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 16 Jul 2019 22:50:53 +0300 Subject: [PATCH 177/315] Revert "Downgrade memory definitions to prevent bootloader destruction" This reverts commit 0635193887f441c2902bbd7232fe9fdd02cb81c7. --- memory-hifive1-revb.x | 12 +++++++++++- memory-hifive1.x | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/memory-hifive1-revb.x b/memory-hifive1-revb.x index 516306c..e9e4bc5 100644 --- a/memory-hifive1-revb.x +++ b/memory-hifive1-revb.x @@ -1,5 +1,15 @@ INCLUDE memory-fe310.x MEMORY { - FLASH : ORIGIN = 0x20010000, LENGTH = 4032K + FLASH : ORIGIN = 0x20000000, LENGTH = 4M } + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +/* Skip first 64k allocated for bootloader */ +_stext = 0x20010000; diff --git a/memory-hifive1.x b/memory-hifive1.x index f38703b..cd55c70 100644 --- a/memory-hifive1.x +++ b/memory-hifive1.x @@ -1,5 +1,15 @@ INCLUDE memory-fe310.x MEMORY { - FLASH : ORIGIN = 0x20400000, LENGTH = 12M + FLASH : ORIGIN = 0x20000000, LENGTH = 16M } + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +/* Skip first 4M allocated for bootloader */ +_stext = 0x20400000; From fa68b807a25c6ae790c9b3173509c882237c35ee Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 16 Jul 2019 23:04:08 +0300 Subject: [PATCH 178/315] Generate a linker script configured for HiFive1 boards --- build.rs | 6 ++++-- hifive1-link.x | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 hifive1-link.x diff --git a/build.rs b/build.rs index e8fd4a3..cde3258 100644 --- a/build.rs +++ b/build.rs @@ -25,15 +25,17 @@ fn main() { match board.as_str() { "hifive1" => { - fs::copy("memory-hifive1.x", out_dir.join("memory.x")).unwrap(); + fs::copy("memory-hifive1.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1.x"); } "hifive1_revb" => { - fs::copy("memory-hifive1-revb.x", out_dir.join("memory.x")).unwrap(); + fs::copy("memory-hifive1-revb.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); } "lofive" => {} other => panic!("Unknown board: {}", other), } + + fs::copy("hifive1-link.x", out_dir.join("hifive1-link.x")).unwrap(); } diff --git a/hifive1-link.x b/hifive1-link.x new file mode 100644 index 0000000..c472d9b --- /dev/null +++ b/hifive1-link.x @@ -0,0 +1,2 @@ +INCLUDE hifive1-memory.x +INCLUDE link.x From a3682e52b5ec128f1e2834b0aa1c6d7a7bbdbed1 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 16 Jul 2019 23:05:30 +0300 Subject: [PATCH 179/315] Bump version (0.8.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 732bd40..876d018 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.7.1" +version = "0.8.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 5d9100cb89c5945ca21ed14234c0986565ffd3bc Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 17 Jul 2019 00:22:27 +0300 Subject: [PATCH 180/315] Fix SPI: deassert CS when transfer completes --- src/spi.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/spi.rs b/src/spi.rs index ae4728f..9a69469 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -211,6 +211,11 @@ impl Spi { } } + /// Finishes transfer by deasserting CS + pub fn end_transfer(&mut self) { + self.cs_mode_word() + } + /// Releases the SPI peripheral and associated pins pub fn free(self) -> (SPI, PINS) { (self.spi, self.pins) @@ -259,6 +264,8 @@ impl embedded_hal::blocking::spi::Transfer for Spi embedded_hal::blocking::spi::Transfer for Spi embedded_hal::blocking::spi::Write for Spi let _ = self.spi.rxdata.read(); } + self.cs_mode_frame(); + let mut iwrite = 0; let mut iread = 0; while iwrite < words.len() || iread < words.len() { @@ -315,6 +326,8 @@ impl embedded_hal::blocking::spi::Write for Spi } } + self.cs_mode_word(); + // Restore watermark levels self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); @@ -345,6 +358,8 @@ impl embedded_hal::blocking::spi::WriteIter for Spi 0 { @@ -363,6 +378,8 @@ impl embedded_hal::blocking::spi::WriteIter for Spi Date: Wed, 17 Jul 2019 00:27:06 +0300 Subject: [PATCH 181/315] Fix SPI docs --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index 9a69469..f49c90f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -21,7 +21,7 @@ //! - MISO: Pin 28 IOF0 //! - SCK: Pin 29 IOF0 //! - SS: Pin 26 IOF0 -//! - Interrupt::QSPI0 +//! - Interrupt::QSPI2 use core::convert::Infallible; use core::ops::Deref; From 5910496431837e2d18bc4eb0089857493477f6f5 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 17 Jul 2019 00:36:02 +0300 Subject: [PATCH 182/315] Fix docs --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index f49c90f..5bf469f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -211,7 +211,7 @@ impl Spi { } } - /// Finishes transfer by deasserting CS + /// Finishes transfer by deasserting CS (only for hardware-controlled CS) pub fn end_transfer(&mut self) { self.cs_mode_word() } From ceb3e7f42f7ce0ef8cfef26bfd43ba5d506f7af3 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 17 Jul 2019 00:36:35 +0300 Subject: [PATCH 183/315] Bump version (0.8.1) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8ebb0bd..3accefb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.8.0" +version = "0.8.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 2562e73d5c3c158051372607f44facca3aded16f Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 27 Jul 2019 15:59:10 -0600 Subject: [PATCH 184/315] add PMUExt --- src/lib.rs | 1 + src/pmu.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/pmu.rs diff --git a/src/lib.rs b/src/lib.rs index cb2f3f0..1326472 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ pub mod spi; pub mod stdout; pub mod time; pub mod wdog; +pub mod pmu; #[cfg(feature = "g002")] pub mod i2c; diff --git a/src/pmu.rs b/src/pmu.rs new file mode 100644 index 0000000..6ae6d45 --- /dev/null +++ b/src/pmu.rs @@ -0,0 +1,93 @@ +//! PMU Extension +#![allow(missing_docs)] +use e310x::{PMU, RTC}; + +/// value required written to pmukey register before writing to other PMU registers +pub const PMU_KEY_VAL: u32 = 0x51F15E; + +const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [ + 0x2F0, // assert corerst + 0x3F0, // assert hfclkrst + 0x3D0, // deassert pmu_out_1 + 0x3C0, // deassert pmu_out_0 + 0x3C0, // repeats + 0x3C0, + 0x3C0, + 0x3C0, +]; + +const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ + 0x3F0, // assert all resets and enable all power supplies + 0x2F8, // idle 2^8 cycles, then deassert hfclkrst + 0x030, // deassert corerst and padrst + 0x030, // repeats + 0x030, + 0x030, + 0x030, + 0x030, +]; + +pub trait PMUExt { + fn configure(&self) -> PMUCfg; +} + +impl PMUExt for PMU { + fn configure(&self) -> PMUCfg { + PMUCfg { + _0: () + } + } +} + +pub struct PMUCfg { + _0: (), +} + +impl PMUCfg { + /// + /// Resets SLEEP and WAKE programs on the PMU to defaults + /// + /// *Registers* + /// - pmukey + /// - pmusleeppm + /// - pmuwakepm + /// + pub fn load_default_programs(&self) { + unsafe { + for i in 0..8 { + (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*PMU::ptr()).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); + + (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*PMU::ptr()).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); + } + } + } + + /// + /// Puts device to sleep for N seconds, allowing wake-up button to wake it up as well + /// + /// *Registers* + /// - pmukey + /// - pmuie + /// - pmusleep + /// - rtccfg + /// - rtccmp + /// + pub fn sleep(&self, sleep_time: u32) { + unsafe { + // set interrupt source to RTC enabled, each pmu register needs key set before write + (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*PMU::ptr()).pmuie.write(|w| w.rtc().set_bit().dwakeup().set_bit()); + // set RTC clock scale to once per second for easy calculation + (*RTC::ptr()).rtccfg.write(|w| w.enalways().set_bit().scale().bits(15)); + // get current RTC clock value scaled + let rtc_now = (*RTC::ptr()).rtcs.read().bits(); + // set RTC clock comparator + (*RTC::ptr()).rtccmp.write(|w| w.bits(rtc_now + sleep_time)); + // go to sleep for sleep_time seconds, need to set pmukey here as well + (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*PMU::ptr()).pmusleep.write(|w| w.sleep().set_bit()); + } + } +} From 679527eb117844d238aec9ac41d3e98590c7828e Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 1 Aug 2019 15:58:24 -0600 Subject: [PATCH 185/315] add backup handling --- src/pmu.rs | 212 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 173 insertions(+), 39 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index 6ae6d45..a03e369 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -1,30 +1,48 @@ //! PMU Extension #![allow(missing_docs)] -use e310x::{PMU, RTC}; +use e310x::{BACKUP, PMU, RTC}; /// value required written to pmukey register before writing to other PMU registers pub const PMU_KEY_VAL: u32 = 0x51F15E; +// Hifive1-revA programs +#[cfg(not(feature = "g002"))] +const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [ + 0x0F0, // assert corerst + 0x1F0, // assert hfclkrst + 0x1D0, // deassert pmu_out_1 + 0x1C0, // deassert pmu_out_0 + 0x1C0, // repeats + 0x1C0, 0x1C0, 0x1C0, +]; + +#[cfg(not(feature = "g002"))] +const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ + 0x1F0, // assert all resets and enable all power supplies + 0x0F8, // idle 2^8 cycles, then deassert hfclkrst + 0x030, // deassert corerst and padrst + 0x030, // repeats + 0x030, 0x030, 0x030, 0x030, +]; + +// Hifive1-revB programs +#[cfg(feature = "g002")] const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [ 0x2F0, // assert corerst 0x3F0, // assert hfclkrst 0x3D0, // deassert pmu_out_1 0x3C0, // deassert pmu_out_0 0x3C0, // repeats - 0x3C0, - 0x3C0, - 0x3C0, + 0x3C0, 0x3C0, 0x3C0, ]; +#[cfg(feature = "g002")] const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ 0x3F0, // assert all resets and enable all power supplies 0x2F8, // idle 2^8 cycles, then deassert hfclkrst 0x030, // deassert corerst and padrst 0x030, // repeats - 0x030, - 0x030, - 0x030, - 0x030, + 0x030, 0x030, 0x030, 0x030, ]; pub trait PMUExt { @@ -33,61 +51,177 @@ pub trait PMUExt { impl PMUExt for PMU { fn configure(&self) -> PMUCfg { - PMUCfg { - _0: () - } + PMUCfg } } -pub struct PMUCfg { - _0: (), +pub struct PMUCfg; + +#[derive(Debug)] +pub enum BackupError { + DataTooLarge, + DataMisaligned, } impl PMUCfg { /// /// Resets SLEEP and WAKE programs on the PMU to defaults - /// - /// *Registers* - /// - pmukey - /// - pmusleeppm - /// - pmuwakepm - /// + /// pub fn load_default_programs(&self) { unsafe { + let pmu = PMU::ptr(); + for i in 0..8 { - (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*PMU::ptr()).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); - (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*PMU::ptr()).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); } } } /// /// Puts device to sleep for N seconds, allowing wake-up button to wake it up as well - /// - /// *Registers* - /// - pmukey - /// - pmuie - /// - pmusleep - /// - rtccfg - /// - rtccmp - /// - pub fn sleep(&self, sleep_time: u32) { + /// + /// *sleep_time* - the amount of time to sleep for in seconds + /// + /// *Performs following changes to RTC* + /// - enables RTC clock to be always on + /// - sets scale to 1/s + /// + pub fn sleep(self, sleep_time: u32) { unsafe { + let pmu = PMU::ptr(); + let rtc = RTC::ptr(); + // set interrupt source to RTC enabled, each pmu register needs key set before write - (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*PMU::ptr()).pmuie.write(|w| w.rtc().set_bit().dwakeup().set_bit()); + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu) + .pmuie + .write(|w| w.rtc().set_bit().dwakeup().set_bit()); // set RTC clock scale to once per second for easy calculation - (*RTC::ptr()).rtccfg.write(|w| w.enalways().set_bit().scale().bits(15)); + (*rtc) + .rtccfg + .write(|w| w.enalways().set_bit().scale().bits(15)); // get current RTC clock value scaled - let rtc_now = (*RTC::ptr()).rtcs.read().bits(); + let rtc_now = (*rtc).rtcs.read().bits(); // set RTC clock comparator - (*RTC::ptr()).rtccmp.write(|w| w.bits(rtc_now + sleep_time)); + (*rtc).rtccmp.write(|w| w.bits(rtc_now + sleep_time)); // go to sleep for sleep_time seconds, need to set pmukey here as well - (*PMU::ptr()).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*PMU::ptr()).pmusleep.write(|w| w.sleep().set_bit()); + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu).pmusleep.write(|w| w.sleep().set_bit()); + } + } + + /// + /// Stores user data `UD` to backup registers. + /// + /// # Arguments + /// + /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registerss + /// + /// # Returns + /// + /// * `Result` - the stored `user_data` is returned on success + /// + /// # Errors + /// + /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers + /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes + /// + /// # Notes + /// + /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` + /// + pub fn store_backup(&self, user_data: UD) -> Result + where + UD: Sized, + { + unsafe { + let backup = BACKUP::ptr(); + let ud_size = core::mem::size_of::(); + + if ud_size > (*backup).backup.len() { + return Err(BackupError::DataTooLarge); + } + + if ud_size % 4 != 0 { + return Err(BackupError::DataMisaligned); + } + + let ptr = &user_data as *const _; + let ptr_u32 = ptr as *const u32; + let sliced = core::slice::from_raw_parts(ptr_u32, ud_size); + + for i in 0..sliced.len() { + (*backup).backup[i].write(|w| w.bits(sliced[i])); + } + + Ok(user_data) + } + } + + /// + /// Stores user data `UD` to backup registers. + /// + /// # Arguments + /// + /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registerss + /// + /// # Returns + /// + /// * `Result` - the restored `user_data` is returned on success + /// + /// # Errors + /// + /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers + /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes + /// + /// # Notes + /// + /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` + /// + pub fn restore_backup(&self, user_data: UD) -> Result + where + UD: Sized, + { + unsafe { + let backup = BACKUP::ptr(); + let ud_size = core::mem::size_of::(); + + if ud_size > (*backup).backup.len() { + return Err(BackupError::DataTooLarge); + } + + if ud_size % 4 != 0 { + return Err(BackupError::DataMisaligned); + } + + let reg_count = ud_size / 4; + + let ptr = &user_data as *const _; + let ptr_u32 = ptr as *mut u32; + let sliced = core::slice::from_raw_parts_mut(ptr_u32, reg_count); + + for i in 0..sliced.len() { + sliced[i] = (*backup).backup[i].read().bits(); + } + + Ok(user_data) + } + } + + /// + /// Clears all backup registers by setting each to zero + /// + pub fn clear_backup(self) { + unsafe { + let backup = BACKUP::ptr(); + + for i in 0..(*backup).backup.len() { + (*backup).backup[i].write(|w| w.bits(0u32)); + } } } } From a3f1510fb29f8de42ae67ae8db4ed6597f7e1165 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 1 Aug 2019 16:07:05 -0600 Subject: [PATCH 186/315] doc beautification --- src/pmu.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index a03e369..835c523 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -84,11 +84,14 @@ impl PMUCfg { /// /// Puts device to sleep for N seconds, allowing wake-up button to wake it up as well /// + /// # Arguments + /// /// *sleep_time* - the amount of time to sleep for in seconds /// - /// *Performs following changes to RTC* - /// - enables RTC clock to be always on - /// - sets scale to 1/s + /// # Notes + /// + /// - enables RTC to be always on + /// - sets RTC scale to 1/s /// pub fn sleep(self, sleep_time: u32) { unsafe { From 14b3f77cbeb3e2e74e38c5a28db3dad0c8da2252 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 2 Aug 2019 15:30:55 -0600 Subject: [PATCH 187/315] fix docs --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index 835c523..10e6cc2 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -166,7 +166,7 @@ impl PMUCfg { } /// - /// Stores user data `UD` to backup registers. + /// Restores user data `UD` from backup registers. /// /// # Arguments /// From 7d9efe695a02dd094f8d051441665e11d0c2d785 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 2 Aug 2019 16:59:49 -0600 Subject: [PATCH 188/315] add wakeup_cause() -> Enum --- src/pmu.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/pmu.rs b/src/pmu.rs index 10e6cc2..cf6c39d 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -45,6 +45,26 @@ const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ 0x030, 0x030, 0x030, 0x030, ]; +/// +/// Enumeration of device reset causes +/// +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ResetCause { + PowerOn, + External, + WatchDog, +} + +/// +/// Enumeration of device wakeup causes +/// +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WakeupCause { + Reset(ResetCause), + RTC, + Digital, +} + pub trait PMUExt { fn configure(&self) -> PMUCfg; } @@ -63,6 +83,11 @@ pub enum BackupError { DataMisaligned, } +#[derive(Debug)] +pub enum CauseError { + InvalidCause, +} + impl PMUCfg { /// /// Resets SLEEP and WAKE programs on the PMU to defaults @@ -227,4 +252,41 @@ impl PMUCfg { } } } + + /// + /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register + /// + /// # Returns + /// + /// * `Result` - the cause enum is returned on success + /// + /// # Errors + /// + /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered + /// + pub fn wakeup_cause(&self) -> Result { + unsafe { + let pmu = PMU::ptr(); + + let pmu_cause = (*pmu).pmucause.read(); + let wakeup_cause = pmu_cause.wakeupcause(); + if wakeup_cause.is_rtc() { + return Ok(WakeupCause::RTC) + } else if wakeup_cause.is_digital() { + return Ok(WakeupCause::Digital) + } else if wakeup_cause.is_reset() { + let reset_cause = pmu_cause.resetcause(); + + if reset_cause.is_power_on() { + return Ok(WakeupCause::Reset(ResetCause::PowerOn)) + } else if reset_cause.is_external() { + return Ok(WakeupCause::Reset(ResetCause::External)) + } else if reset_cause.is_watchdog() { + return Ok(WakeupCause::Reset(ResetCause::WatchDog)) + } + } + + Err(CauseError::InvalidCause) + } + } } From 051ae3dc03414d6cc5cf919d5a94681ae92094c7 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 2 Aug 2019 17:03:28 -0600 Subject: [PATCH 189/315] fix doc typo --- src/pmu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index cf6c39d..f8cc4cf 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -147,7 +147,7 @@ impl PMUCfg { /// /// # Arguments /// - /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registerss + /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registers /// /// # Returns /// @@ -195,7 +195,7 @@ impl PMUCfg { /// /// # Arguments /// - /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registerss + /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registers /// /// # Returns /// From 7b98d3a0bb6d38e37dad96e49623294fc644d04c Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 4 Aug 2019 15:31:06 -0600 Subject: [PATCH 190/315] extend PMU directly --- src/pmu.rs | 188 +++++++++++++++++++++++++++++------------------------ 1 file changed, 102 insertions(+), 86 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index f8cc4cf..560e912 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -50,8 +50,11 @@ const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ResetCause { + /// Reset due to power on PowerOn, + /// Reset due to external input (button) External, + /// Reset due to watchdog WatchDog, } @@ -60,51 +63,38 @@ pub enum ResetCause { /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WakeupCause { + /// Wake up due to reset (see ResetCause) Reset(ResetCause), + /// Wake up due to RTC clock RTC, + /// Wake up due to digital input (button) Digital, } -pub trait PMUExt { - fn configure(&self) -> PMUCfg; -} - -impl PMUExt for PMU { - fn configure(&self) -> PMUCfg { - PMUCfg - } -} - -pub struct PMUCfg; - +/// +/// Errors for user data backup procedures +/// #[derive(Debug)] pub enum BackupError { - DataTooLarge, + /// Emitted when user data is larger than backup registers capacity + DataTooLarge, + /// Emitted when user data is not aligned to 4 bytes or more DataMisaligned, } +/// +/// Wakeup/Reset cause errors +/// #[derive(Debug)] pub enum CauseError { InvalidCause, } -impl PMUCfg { +pub trait PMUExt { /// /// Resets SLEEP and WAKE programs on the PMU to defaults /// - pub fn load_default_programs(&self) { - unsafe { - let pmu = PMU::ptr(); - - for i in 0..8 { - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); - - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); - } - } - } + fn load_default_programs(&self); /// /// Puts device to sleep for N seconds, allowing wake-up button to wake it up as well @@ -118,7 +108,87 @@ impl PMUCfg { /// - enables RTC to be always on /// - sets RTC scale to 1/s /// - pub fn sleep(self, sleep_time: u32) { + fn sleep(self, sleep_time: u32); + + /// + /// Stores user data `UD` to backup registers. + /// + /// # Arguments + /// + /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registers + /// + /// # Returns + /// + /// * `Result` - the stored `user_data` is returned on success + /// + /// # Errors + /// + /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers + /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes + /// + /// # Notes + /// + /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` + /// + fn store_backup(&self, user_data: UD) -> Result; + + /// + /// Restores user data `UD` from backup registers. + /// + /// # Arguments + /// + /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registers + /// + /// # Returns + /// + /// * `Result` - the restored `user_data` is returned on success + /// + /// # Errors + /// + /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers + /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes + /// + /// # Notes + /// + /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` + /// + fn restore_backup(&self, user_data: UD) -> Result; + + /// + /// Clears all backup registers by setting each to zero + /// + fn clear_backup(&self); + + /// + /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register + /// + /// # Returns + /// + /// * `Result` - the cause enum is returned on success + /// + /// # Errors + /// + /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered + /// + fn wakeup_cause(&self) -> Result; +} + +impl PMUExt for PMU { + fn load_default_programs(&self) { + unsafe { + let pmu = PMU::ptr(); + + for i in 0..8 { + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); + + (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); + (*pmu).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); + } + } + } + + fn sleep(self, sleep_time: u32) { unsafe { let pmu = PMU::ptr(); let rtc = RTC::ptr(); @@ -142,27 +212,7 @@ impl PMUCfg { } } - /// - /// Stores user data `UD` to backup registers. - /// - /// # Arguments - /// - /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registers - /// - /// # Returns - /// - /// * `Result` - the stored `user_data` is returned on success - /// - /// # Errors - /// - /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers - /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes - /// - /// # Notes - /// - /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` - /// - pub fn store_backup(&self, user_data: UD) -> Result + fn store_backup(&self, user_data: UD) -> Result where UD: Sized, { @@ -190,27 +240,7 @@ impl PMUCfg { } } - /// - /// Restores user data `UD` from backup registers. - /// - /// # Arguments - /// - /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registers - /// - /// # Returns - /// - /// * `Result` - the restored `user_data` is returned on success - /// - /// # Errors - /// - /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers - /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes - /// - /// # Notes - /// - /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` - /// - pub fn restore_backup(&self, user_data: UD) -> Result + fn restore_backup(&self, user_data: UD) -> Result where UD: Sized, { @@ -240,10 +270,7 @@ impl PMUCfg { } } - /// - /// Clears all backup registers by setting each to zero - /// - pub fn clear_backup(self) { + fn clear_backup(&self) { unsafe { let backup = BACKUP::ptr(); @@ -253,18 +280,7 @@ impl PMUCfg { } } - /// - /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register - /// - /// # Returns - /// - /// * `Result` - the cause enum is returned on success - /// - /// # Errors - /// - /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered - /// - pub fn wakeup_cause(&self) -> Result { + fn wakeup_cause(&self) -> Result { unsafe { let pmu = PMU::ptr(); From bc813bf30a62a2916621735381bf4a664fa50a3b Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 5 Aug 2019 12:34:48 -0600 Subject: [PATCH 191/315] use self where appropriate --- src/pmu.rs | 63 ++++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index 560e912..e6d0ec0 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -176,39 +176,32 @@ pub trait PMUExt { impl PMUExt for PMU { fn load_default_programs(&self) { unsafe { - let pmu = PMU::ptr(); - for i in 0..8 { - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu).pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); + self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); + self.pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu).pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); + self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); + self.pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); } } } fn sleep(self, sleep_time: u32) { unsafe { - let pmu = PMU::ptr(); let rtc = RTC::ptr(); // set interrupt source to RTC enabled, each pmu register needs key set before write - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu) - .pmuie - .write(|w| w.rtc().set_bit().dwakeup().set_bit()); + self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); + self.pmuie.write(|w| w.rtc().set_bit().dwakeup().set_bit()); // set RTC clock scale to once per second for easy calculation - (*rtc) - .rtccfg - .write(|w| w.enalways().set_bit().scale().bits(15)); + (*rtc).rtccfg.write(|w| w.enalways().set_bit().scale().bits(15)); // get current RTC clock value scaled let rtc_now = (*rtc).rtcs.read().bits(); // set RTC clock comparator (*rtc).rtccmp.write(|w| w.bits(rtc_now + sleep_time)); // go to sleep for sleep_time seconds, need to set pmukey here as well - (*pmu).pmukey.write(|w| w.bits(PMU_KEY_VAL)); - (*pmu).pmusleep.write(|w| w.sleep().set_bit()); + self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); + self.pmusleep.write(|w| w.sleep().set_bit()); } } @@ -281,28 +274,24 @@ impl PMUExt for PMU { } fn wakeup_cause(&self) -> Result { - unsafe { - let pmu = PMU::ptr(); - - let pmu_cause = (*pmu).pmucause.read(); - let wakeup_cause = pmu_cause.wakeupcause(); - if wakeup_cause.is_rtc() { - return Ok(WakeupCause::RTC) - } else if wakeup_cause.is_digital() { - return Ok(WakeupCause::Digital) - } else if wakeup_cause.is_reset() { - let reset_cause = pmu_cause.resetcause(); - - if reset_cause.is_power_on() { - return Ok(WakeupCause::Reset(ResetCause::PowerOn)) - } else if reset_cause.is_external() { - return Ok(WakeupCause::Reset(ResetCause::External)) - } else if reset_cause.is_watchdog() { - return Ok(WakeupCause::Reset(ResetCause::WatchDog)) - } + let pmu_cause = self.pmucause.read(); + let wakeup_cause = pmu_cause.wakeupcause(); + if wakeup_cause.is_rtc() { + return Ok(WakeupCause::RTC) + } else if wakeup_cause.is_digital() { + return Ok(WakeupCause::Digital) + } else if wakeup_cause.is_reset() { + let reset_cause = pmu_cause.resetcause(); + + if reset_cause.is_power_on() { + return Ok(WakeupCause::Reset(ResetCause::PowerOn)) + } else if reset_cause.is_external() { + return Ok(WakeupCause::Reset(ResetCause::External)) + } else if reset_cause.is_watchdog() { + return Ok(WakeupCause::Reset(ResetCause::WatchDog)) } - - Err(CauseError::InvalidCause) } + + Err(CauseError::InvalidCause) } } From ce11b034284ff57f89e2c48457ada93dc9dbb116 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 5 Aug 2019 17:02:56 -0600 Subject: [PATCH 192/315] fix size_of checks and slicing --- src/pmu.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index e6d0ec0..ecdbccc 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -2,6 +2,9 @@ #![allow(missing_docs)] use e310x::{BACKUP, PMU, RTC}; +/// Backup register size in bytes +const BACKUP_REGISTER_BYTES: usize = 4usize; + /// value required written to pmukey register before writing to other PMU registers pub const PMU_KEY_VAL: u32 = 0x51F15E; @@ -213,17 +216,19 @@ impl PMUExt for PMU { let backup = BACKUP::ptr(); let ud_size = core::mem::size_of::(); - if ud_size > (*backup).backup.len() { + if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { return Err(BackupError::DataTooLarge); } - if ud_size % 4 != 0 { + if ud_size % BACKUP_REGISTER_BYTES != 0 { return Err(BackupError::DataMisaligned); } + let reg_count = ud_size / BACKUP_REGISTER_BYTES; + let ptr = &user_data as *const _; let ptr_u32 = ptr as *const u32; - let sliced = core::slice::from_raw_parts(ptr_u32, ud_size); + let sliced = core::slice::from_raw_parts(ptr_u32, reg_count); for i in 0..sliced.len() { (*backup).backup[i].write(|w| w.bits(sliced[i])); @@ -245,11 +250,11 @@ impl PMUExt for PMU { return Err(BackupError::DataTooLarge); } - if ud_size % 4 != 0 { + if ud_size % BACKUP_REGISTER_BYTES != 0 { return Err(BackupError::DataMisaligned); } - let reg_count = ud_size / 4; + let reg_count = ud_size / BACKUP_REGISTER_BYTES; let ptr = &user_data as *const _; let ptr_u32 = ptr as *mut u32; From fac54627953666584c9adf4dac1b84e70df4d486 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 6 Aug 2019 09:43:18 -0600 Subject: [PATCH 193/315] fix forgotten check --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index ecdbccc..ea4c618 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -246,7 +246,7 @@ impl PMUExt for PMU { let backup = BACKUP::ptr(); let ud_size = core::mem::size_of::(); - if ud_size > (*backup).backup.len() { + if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { return Err(BackupError::DataTooLarge); } From df40232251a062c5fd3a3e08714cf05cd219aec8 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 6 Aug 2019 09:43:48 -0600 Subject: [PATCH 194/315] remove unnecessary literal type annotation --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index ea4c618..59e0489 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -3,7 +3,7 @@ use e310x::{BACKUP, PMU, RTC}; /// Backup register size in bytes -const BACKUP_REGISTER_BYTES: usize = 4usize; +const BACKUP_REGISTER_BYTES: usize = 4; /// value required written to pmukey register before writing to other PMU registers pub const PMU_KEY_VAL: u32 = 0x51F15E; From 8415d54669aba7a85e6ceeff3b17ff224846e90d Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 6 Aug 2019 11:33:40 -0600 Subject: [PATCH 195/315] fix misalignment -> size invalid error + use reference on store --- src/pmu.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index 59e0489..418e302 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -81,8 +81,8 @@ pub enum WakeupCause { pub enum BackupError { /// Emitted when user data is larger than backup registers capacity DataTooLarge, - /// Emitted when user data is not aligned to 4 bytes or more - DataMisaligned, + /// Emitted when user data size is not divisible by 4 bytes + DataSizeInvalid, } /// @@ -118,29 +118,29 @@ pub trait PMUExt { /// /// # Arguments /// - /// * `user_data` - the user data to store. *MUST* have alignment of at least 4 and fit into the backup registers + /// * `user_data` - reference to the user data to store. `user_data` size must by divisible by 4 bytes /// /// # Returns /// - /// * `Result` - the stored `user_data` is returned on success + /// * `Result<(), BackupError>` - `()` is returned on success /// /// # Errors /// /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers - /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes + /// * `BackupError::DataSizeInvalid` - returned if `user_data` size is not divisible by 4 bytes /// /// # Notes /// /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` /// - fn store_backup(&self, user_data: UD) -> Result; + fn store_backup(&self, user_data: &UD) -> Result<(), BackupError>; /// /// Restores user data `UD` from backup registers. /// /// # Arguments /// - /// * `user_data` - the user data to restore to. *MUST* have alignment of at least 4 and fit into the backup registers + /// * `user_data` - the user data to restore to. `user_data` size must by divisible by 4 bytes /// /// # Returns /// @@ -149,8 +149,7 @@ pub trait PMUExt { /// # Errors /// /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers - /// * `BackupError::DataMisaligned` - returned if `user_data` is not aligned to at least 4 bytes - /// + /// * `BackupError::DataSizeInvalid` - returned if `user_data` size is not divisible by 4 bytes /// /// # Notes /// /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` @@ -208,7 +207,7 @@ impl PMUExt for PMU { } } - fn store_backup(&self, user_data: UD) -> Result + fn store_backup(&self, user_data: &UD) -> Result<(), BackupError> where UD: Sized, { @@ -221,12 +220,12 @@ impl PMUExt for PMU { } if ud_size % BACKUP_REGISTER_BYTES != 0 { - return Err(BackupError::DataMisaligned); + return Err(BackupError::DataSizeInvalid); } let reg_count = ud_size / BACKUP_REGISTER_BYTES; - let ptr = &user_data as *const _; + let ptr = user_data as *const _; let ptr_u32 = ptr as *const u32; let sliced = core::slice::from_raw_parts(ptr_u32, reg_count); @@ -234,7 +233,7 @@ impl PMUExt for PMU { (*backup).backup[i].write(|w| w.bits(sliced[i])); } - Ok(user_data) + Ok(()) } } @@ -251,7 +250,7 @@ impl PMUExt for PMU { } if ud_size % BACKUP_REGISTER_BYTES != 0 { - return Err(BackupError::DataMisaligned); + return Err(BackupError::DataSizeInvalid); } let reg_count = ud_size / BACKUP_REGISTER_BYTES; From 4144c9b10cf09cb588ea3383e0f0e474ac7d8bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Katona?= Date: Thu, 8 Aug 2019 10:28:42 -0600 Subject: [PATCH 196/315] Update src/pmu.rs Co-Authored-By: Vadim Kaushan --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index 418e302..946640d 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -8,7 +8,7 @@ const BACKUP_REGISTER_BYTES: usize = 4; /// value required written to pmukey register before writing to other PMU registers pub const PMU_KEY_VAL: u32 = 0x51F15E; -// Hifive1-revA programs +// HiFive1 (Rev A) programs #[cfg(not(feature = "g002"))] const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [ 0x0F0, // assert corerst From ba29ff426ad9b309ad593fb82668018f542a2334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Katona?= Date: Thu, 8 Aug 2019 10:30:36 -0600 Subject: [PATCH 197/315] Update src/pmu.rs Co-Authored-By: Vadim Kaushan --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index 946640d..6ad75e9 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -28,7 +28,7 @@ const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ 0x030, 0x030, 0x030, 0x030, ]; -// Hifive1-revB programs +// HiFive1 Rev B programs #[cfg(feature = "g002")] const DEFAULT_SLEEP_PROGRAM: [u32; 8] = [ 0x2F0, // assert corerst From 580344cc5da58145e5f4146322979efee6d5a2d2 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 8 Aug 2019 10:42:04 -0600 Subject: [PATCH 198/315] use iterator + doc coverage --- src/pmu.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index 418e302..f093493 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -90,6 +90,7 @@ pub enum BackupError { /// #[derive(Debug)] pub enum CauseError { + /// Emitted if an unknown wakeup or reset cause is encountered InvalidCause, } @@ -271,8 +272,8 @@ impl PMUExt for PMU { unsafe { let backup = BACKUP::ptr(); - for i in 0..(*backup).backup.len() { - (*backup).backup[i].write(|w| w.bits(0u32)); + for backup_r in &(*backup).backup { + backup_r.write(|w| w.bits(0u32)); } } } From 57bc7a8ce865594679e7598af4684043c81b694b Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 8 Aug 2019 12:12:57 -0600 Subject: [PATCH 199/315] make backup store/restore unsafe + warnings --- src/pmu.rs | 173 +++++++++++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 84 deletions(-) diff --git a/src/pmu.rs b/src/pmu.rs index d7be7c8..decdef9 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -114,8 +114,29 @@ pub trait PMUExt { /// fn sleep(self, sleep_time: u32); + /// + /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register + /// + /// # Returns + /// + /// * `Result` - the cause enum is returned on success + /// + /// # Errors + /// + /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered + /// + fn wakeup_cause(&self) -> Result; + /// /// Stores user data `UD` to backup registers. + /// + /// # *WARNING* + /// + /// `user_data` value must not contain un-serializable types such as pointers or references. + /// + /// `user_data` must be divisible by 4 bytes. + /// + /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` /// /// # Arguments /// @@ -130,50 +151,38 @@ pub trait PMUExt { /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers /// * `BackupError::DataSizeInvalid` - returned if `user_data` size is not divisible by 4 bytes /// - /// # Notes - /// - /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` - /// - fn store_backup(&self, user_data: &UD) -> Result<(), BackupError>; + unsafe fn store_backup(&self, user_data: &UD) -> Result<(), BackupError>; /// /// Restores user data `UD` from backup registers. /// + /// # *WARNING* + /// + /// `user_data` value must not contain un-serializable types such as pointers or references. + /// + /// `user_data` must be divisible by 4 bytes. + /// + /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` + /// /// # Arguments /// /// * `user_data` - the user data to restore to. `user_data` size must by divisible by 4 bytes /// /// # Returns /// - /// * `Result` - the restored `user_data` is returned on success + /// * `Result<(), BackupError>` - `()` is returned on success /// /// # Errors /// /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers /// * `BackupError::DataSizeInvalid` - returned if `user_data` size is not divisible by 4 bytes /// - /// # Notes - /// - /// You can use `#[repr(align(4))]` to enforce a minimum alignment of 4 bytes for `user_data` - /// - fn restore_backup(&self, user_data: UD) -> Result; + /// + unsafe fn restore_backup(&self, user_data: &mut UD) -> Result<(), BackupError>; /// /// Clears all backup registers by setting each to zero /// fn clear_backup(&self); - - /// - /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register - /// - /// # Returns - /// - /// * `Result` - the cause enum is returned on success - /// - /// # Errors - /// - /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered - /// - fn wakeup_cause(&self) -> Result; } impl PMUExt for PMU { @@ -208,64 +217,82 @@ impl PMUExt for PMU { } } - fn store_backup(&self, user_data: &UD) -> Result<(), BackupError> + fn wakeup_cause(&self) -> Result { + let pmu_cause = self.pmucause.read(); + let wakeup_cause = pmu_cause.wakeupcause(); + if wakeup_cause.is_rtc() { + return Ok(WakeupCause::RTC) + } else if wakeup_cause.is_digital() { + return Ok(WakeupCause::Digital) + } else if wakeup_cause.is_reset() { + let reset_cause = pmu_cause.resetcause(); + + if reset_cause.is_power_on() { + return Ok(WakeupCause::Reset(ResetCause::PowerOn)) + } else if reset_cause.is_external() { + return Ok(WakeupCause::Reset(ResetCause::External)) + } else if reset_cause.is_watchdog() { + return Ok(WakeupCause::Reset(ResetCause::WatchDog)) + } + } + + Err(CauseError::InvalidCause) + } + + unsafe fn store_backup(&self, user_data: &UD) -> Result<(), BackupError> where UD: Sized, { - unsafe { - let backup = BACKUP::ptr(); - let ud_size = core::mem::size_of::(); - - if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { - return Err(BackupError::DataTooLarge); - } + let backup = BACKUP::ptr(); + let ud_size = core::mem::size_of::(); - if ud_size % BACKUP_REGISTER_BYTES != 0 { - return Err(BackupError::DataSizeInvalid); - } + if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { + return Err(BackupError::DataTooLarge); + } - let reg_count = ud_size / BACKUP_REGISTER_BYTES; + if ud_size % BACKUP_REGISTER_BYTES != 0 { + return Err(BackupError::DataSizeInvalid); + } - let ptr = user_data as *const _; - let ptr_u32 = ptr as *const u32; - let sliced = core::slice::from_raw_parts(ptr_u32, reg_count); + let reg_count = ud_size / BACKUP_REGISTER_BYTES; - for i in 0..sliced.len() { - (*backup).backup[i].write(|w| w.bits(sliced[i])); - } + let ptr = user_data as *const _; + let ptr_u32 = ptr as *const u32; + let sliced = core::slice::from_raw_parts(ptr_u32, reg_count); - Ok(()) + for i in 0..sliced.len() { + (*backup).backup[i].write(|w| w.bits(sliced[i])); } + + Ok(()) } - fn restore_backup(&self, user_data: UD) -> Result + unsafe fn restore_backup(&self, user_data: &mut UD) -> Result<(), BackupError> where UD: Sized, { - unsafe { - let backup = BACKUP::ptr(); - let ud_size = core::mem::size_of::(); + let backup = BACKUP::ptr(); + let ud_size = core::mem::size_of::(); - if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { - return Err(BackupError::DataTooLarge); - } - - if ud_size % BACKUP_REGISTER_BYTES != 0 { - return Err(BackupError::DataSizeInvalid); - } + if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { + return Err(BackupError::DataTooLarge); + } - let reg_count = ud_size / BACKUP_REGISTER_BYTES; + if ud_size % BACKUP_REGISTER_BYTES != 0 { + return Err(BackupError::DataSizeInvalid); + } - let ptr = &user_data as *const _; - let ptr_u32 = ptr as *mut u32; - let sliced = core::slice::from_raw_parts_mut(ptr_u32, reg_count); + let reg_count = ud_size / BACKUP_REGISTER_BYTES; - for i in 0..sliced.len() { - sliced[i] = (*backup).backup[i].read().bits(); - } + let ptr = user_data as *const _; + let ptr_u32 = ptr as *mut u32; + let sliced = core::slice::from_raw_parts_mut(ptr_u32, reg_count); - Ok(user_data) + for i in 0..sliced.len() { + sliced[i] = (*backup).backup[i].read().bits(); } + + Ok(()) } fn clear_backup(&self) { @@ -277,26 +304,4 @@ impl PMUExt for PMU { } } } - - fn wakeup_cause(&self) -> Result { - let pmu_cause = self.pmucause.read(); - let wakeup_cause = pmu_cause.wakeupcause(); - if wakeup_cause.is_rtc() { - return Ok(WakeupCause::RTC) - } else if wakeup_cause.is_digital() { - return Ok(WakeupCause::Digital) - } else if wakeup_cause.is_reset() { - let reset_cause = pmu_cause.resetcause(); - - if reset_cause.is_power_on() { - return Ok(WakeupCause::Reset(ResetCause::PowerOn)) - } else if reset_cause.is_external() { - return Ok(WakeupCause::Reset(ResetCause::External)) - } else if reset_cause.is_watchdog() { - return Ok(WakeupCause::Reset(ResetCause::WatchDog)) - } - } - - Err(CauseError::InvalidCause) - } } From 1562db5dc6a7250a69a7ba86712f74f4410e324e Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 8 Aug 2019 12:17:25 -0600 Subject: [PATCH 200/315] add compiler version warnings --- src/pmu.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pmu.rs b/src/pmu.rs index decdef9..27ed780 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -136,6 +136,8 @@ pub trait PMUExt { /// /// `user_data` must be divisible by 4 bytes. /// + /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** + /// /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` /// /// # Arguments @@ -162,6 +164,8 @@ pub trait PMUExt { /// /// `user_data` must be divisible by 4 bytes. /// + /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** + /// /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` /// /// # Arguments From ed0d4a437827f9db462ae15bf96765a6b5e2cae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Katona?= Date: Thu, 8 Aug 2019 13:27:13 -0600 Subject: [PATCH 201/315] Update src/pmu.rs Co-Authored-By: Vadim Kaushan --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index 27ed780..768ba36 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -134,7 +134,7 @@ pub trait PMUExt { /// /// `user_data` value must not contain un-serializable types such as pointers or references. /// - /// `user_data` must be divisible by 4 bytes. + /// `user_data` size must be divisible by 4 bytes. /// /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** /// From f8cded2f409b737802bd9a424fdbc052db7798e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Katona?= Date: Thu, 8 Aug 2019 13:27:20 -0600 Subject: [PATCH 202/315] Update src/pmu.rs Co-Authored-By: Vadim Kaushan --- src/pmu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pmu.rs b/src/pmu.rs index 768ba36..11d134c 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -162,7 +162,7 @@ pub trait PMUExt { /// /// `user_data` value must not contain un-serializable types such as pointers or references. /// - /// `user_data` must be divisible by 4 bytes. + /// `user_data` size must be divisible by 4 bytes. /// /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** /// From ec3f20e0ac3b33cd84f085a02640450ae2298d99 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 1 Sep 2019 19:42:47 -0600 Subject: [PATCH 203/315] bump release --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3accefb..8bcce27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.8.1" +version = "0.8.2" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 88fd39598bdc02d15c63807b15b8ca5e74f3c32c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 2 Sep 2019 11:18:54 +0300 Subject: [PATCH 204/315] Update riscv dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3accefb..49025c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" -riscv = "0.5.3" +riscv = "0.5.4" e310x = { version = "0.6.0", features = ["rt"] } [features] From 1b7af14a015f1d8fa784c6598974b1b903cdc64c Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 2 Sep 2019 11:19:07 +0300 Subject: [PATCH 205/315] Revert "Remove mhpmcounters (not present in riscv yet)" This reverts commit 8628649c2bb17c7be25ab26c9ccd9f357fe66817. --- src/core/counters.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/core/counters.rs b/src/core/counters.rs index f461b63..bc98508 100644 --- a/src/core/counters.rs +++ b/src/core/counters.rs @@ -1,6 +1,6 @@ //! Performance counters -use riscv::register::{mcycle, minstret}; +use riscv::register::{mcycle, minstret, mhpmcounter3, mhpmcounter4}; /// Opaque mcycle register pub struct MCYCLE; @@ -24,6 +24,27 @@ impl MINSTRET { } } +/// Opaque mhpmcounter3 register. +pub struct MHPMCOUNTER3; + +impl MHPMCOUNTER3 { + /// Read mhpmcounter3 and mhpmcounter3h registers. + #[inline] + pub fn value(&self) -> u64 { + mhpmcounter3::read64() + } +} + +/// Opaque mhpmcounter4 register. +pub struct MHPMCOUNTER4; + +impl MHPMCOUNTER4 { + /// Read mhpmcounter4 and mhpmcounter4h registers. + #[inline] + pub fn value(&self) -> u64 { + mhpmcounter4::read64() + } +} /// Performance counters pub struct PerformanceCounters { @@ -31,8 +52,11 @@ pub struct PerformanceCounters { pub mcycle: MCYCLE, /// 64-bit minstret counter pub minstret: MINSTRET, + /// 40-bit mhpmcounter3 counter + pub mhpmcounter3: MHPMCOUNTER3, + /// 40-bit mhpmcounter4 counter + pub mhpmcounter4: MHPMCOUNTER4, - // TODO: mhpmcounter3, mhpmcounter4 // TODO: mhpmevent3, mhpmevent4 } @@ -41,6 +65,8 @@ impl PerformanceCounters { Self { mcycle: MCYCLE, minstret: MINSTRET, + mhpmcounter3: MHPMCOUNTER3, + mhpmcounter4: MHPMCOUNTER4 } } } From 49be05ad40b5d1489c0685dbd99a9dae91d0b932 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 7 Sep 2019 11:28:13 +0200 Subject: [PATCH 206/315] readme: fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4179dab..cb05b3c 100644 --- a/README.md +++ b/README.md @@ -33,4 +33,4 @@ Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises to intervene to uphold that code of conduct. [CoC]: CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-riscv-team +[team]: https://github.com/rust-embedded/wg#the-risc-v-team From a9da833d1e57fdc2ff2d565990af0d721385ba95 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 7 Sep 2019 11:34:38 +0200 Subject: [PATCH 207/315] readme: fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b85820..3c9dfd0 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,4 @@ Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises to intervene to uphold that code of conduct. [CoC]: CODE_OF_CONDUCT.md -[team]: https://github.com/rust-embedded/wg#the-riscv-team +[team]: https://github.com/rust-embedded/wg#the-risc-v-team From 9f12be56d2c2cdef7a0bb055620b3118847b65dd Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 6 Nov 2019 19:20:22 +0300 Subject: [PATCH 208/315] Fix clock setup for lofive board --- src/clock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clock.rs b/src/clock.rs index 84fb9d4..22d18df 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -31,7 +31,6 @@ pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); let aonclk = aonclk.constrain(); - let aonclk = aonclk.use_external(Hertz(32_768)); Clocks::freeze(coreclk, aonclk) } From 2776fac8d1822e0f9c8ff4ddc71eb4a96e86513f Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Wed, 6 Nov 2019 11:59:41 -0800 Subject: [PATCH 209/315] added support for the LoFive R1 (#17) * added support for the LoFive R1 * corrected src/clock.rs * added CI rule for `board-lofive-r1` feature * added linkerscript for the LoFive R1 Note that this linkerscript assumes the bootloader is installed. Instructions on how to do that can be found here: https://github.com/mwelling/lofive/wiki#programming-to-lofive-r1-using-the-new-sdk It'll "work" without the bootloader, but user code won't start after a reset. --- Cargo.toml | 1 + build.rs | 4 ++++ ci/script.sh | 1 + memory-lofive-r1.x | 15 +++++++++++++++ src/clock.rs | 6 +++--- 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 memory-lofive-r1.x diff --git a/Cargo.toml b/Cargo.toml index 876d018..84d6b42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ nb = "0.1.2" board-hifive1 = [] board-hifive1-revb = ["e310x-hal/g002"] board-lofive = [] +board-lofive-r1 = ["e310x-hal/g002"] [package.metadata.docs.rs] features = ['board-hifive1-revb'] diff --git a/build.rs b/build.rs index cde3258..a963519 100644 --- a/build.rs +++ b/build.rs @@ -33,6 +33,10 @@ fn main() { println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); } "lofive" => {} + "lofive_r1" => { + fs::copy("memory-lofive-r1.x", out_dir.join("hifive1-memory.x")).unwrap(); + println!("cargo:rerun-if-changed=memory-lofive-r1.x"); + } other => panic!("Unknown board: {}", other), } diff --git a/ci/script.sh b/ci/script.sh index 29cd4d2..0dd41cd 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -5,3 +5,4 @@ set -euxo pipefail cargo check --target $TARGET --features 'board-hifive1' cargo check --target $TARGET --features 'board-hifive1-revb' cargo check --target $TARGET --features 'board-lofive' +cargo check --target $TARGET --features 'board-lofive-r1' diff --git a/memory-lofive-r1.x b/memory-lofive-r1.x new file mode 100644 index 0000000..cd55c70 --- /dev/null +++ b/memory-lofive-r1.x @@ -0,0 +1,15 @@ +INCLUDE memory-fe310.x +MEMORY +{ + FLASH : ORIGIN = 0x20000000, LENGTH = 16M +} + +REGION_ALIAS("REGION_TEXT", FLASH); +REGION_ALIAS("REGION_RODATA", FLASH); +REGION_ALIAS("REGION_DATA", RAM); +REGION_ALIAS("REGION_BSS", RAM); +REGION_ALIAS("REGION_HEAP", RAM); +REGION_ALIAS("REGION_STACK", RAM); + +/* Skip first 4M allocated for bootloader */ +_stext = 0x20400000; diff --git a/src/clock.rs b/src/clock.rs index 22d18df..3081152 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -21,11 +21,11 @@ pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { Clocks::freeze(coreclk, aonclk) } -#[cfg(feature = "board-lofive")] +#[cfg(any(feature = "board-lofive", feature = "board-lofive-r1"))] /// Configures clock generation system. /// -/// For LoFive board external oscillator is enabled for high-frequency clock. -/// For low-frequency clock internal oscillator is used. +/// For the LoFive and LoFive R1 boards, external oscillator is enabled for +/// high-frequency clock. For low-frequency clock internal oscillator is used. pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); From 0f39dd4a936258850959c51edab8c25f2ae25421 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Wed, 6 Nov 2019 23:02:53 +0300 Subject: [PATCH 210/315] Bump version (0.8.1) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 84d6b42..3b4d39c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.8.0" +version = "0.8.1" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 9940676e70b99bc4c44aba1c80e18e31dd3af603 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Mon, 16 Dec 2019 18:08:54 -0800 Subject: [PATCH 211/315] fixed PeripheralAccess::value() The lack of `& 1` caused using pins other than the highest numbered one as an input to not work correctly due to misinterpreting garbage bits as setting the pin in the high state. `&`ing with `1` solves this problem by zeroing out bits that should be ignored. --- src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpio.rs b/src/gpio.rs index c0c0cf3..beae287 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -75,7 +75,7 @@ trait PeripheralAccess { fn value(index: usize) -> bool { let p = Self::peripheral(); - (p.value.read().bits() >> (index & 31)) != 0 + (p.value.read().bits() >> (index & 31) & 1) != 0 } fn set_input_en(index: usize, bit: bool) { From 586dc1a481c07327d085717c5c289928d907c8c4 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 17 Dec 2019 13:51:42 +0300 Subject: [PATCH 212/315] Bump version (0.8.3) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d315d0a..116b000 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.8.2" +version = "0.8.3" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 3a122cc37c0c77b2158f23b83f119ff1768b27f0 Mon Sep 17 00:00:00 2001 From: PinkNoize <21967246+PinkNoize@users.noreply.github.com> Date: Wed, 25 Dec 2019 23:02:23 -0800 Subject: [PATCH 213/315] Merge pull request #18 from PinkNoize/master Return serial rx half from stdout::configure() --- src/stdout.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/stdout.rs b/src/stdout.rs index 147a605..2626773 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -4,7 +4,7 @@ use core::fmt; use nb::block; use riscv::interrupt; use e310x_hal::{ - serial::{Serial, Tx}, + serial::{Serial, Tx, Rx}, gpio::gpio0::{Pin17, Pin16}, time::Bps, clock::Clocks, @@ -43,17 +43,18 @@ impl core::fmt::Write for SerialWrapper { pub fn configure( uart: UART0, tx: Pin17, rx: Pin16, baud_rate: Bps, clocks: Clocks -) { +) -> Rx { let tx = tx.into_iof0(); let rx = rx.into_iof0(); let serial = Serial::new(uart, (tx, rx), baud_rate, clocks); - let (tx, _) = serial.split(); + let (tx, rx) = serial.split(); interrupt::free(|_| { unsafe { STDOUT.replace(SerialWrapper(tx)); } - }) + }); + return rx; } /// Writes string to stdout From 53e9eb013345211360002d536304f0da6cd332bd Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 12 Nov 2019 11:43:46 +0300 Subject: [PATCH 214/315] Update e310x dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 116b000..682885f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" riscv = "0.5.4" -e310x = { version = "0.6.0", features = ["rt"] } +e310x = { version = "0.7.0", features = ["rt"] } [features] g002 = ["e310x/g002"] From d000f7e7562fc513ff52bdc313b9397069c9e4cb Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 12 Nov 2019 11:45:08 +0300 Subject: [PATCH 215/315] Fix gpio driver --- src/gpio.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index beae287..34bf8f8 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -73,9 +73,9 @@ fn atomic_set_bit(r: &AtomicU32, index: usize, bit: bool) { trait PeripheralAccess { fn peripheral() -> &'static e310x::gpio0::RegisterBlock; - fn value(index: usize) -> bool { + fn input_value(index: usize) -> bool { let p = Self::peripheral(); - (p.value.read().bits() >> (index & 31) & 1) != 0 + (p.input_val.read().bits() >> (index & 31) & 1) != 0 } fn set_input_en(index: usize, bit: bool) { @@ -90,15 +90,15 @@ trait PeripheralAccess { atomic_set_bit(r, index, bit); } - fn set_port(index: usize, bit: bool) { + fn set_output_value(index: usize, bit: bool) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.port) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(&p.output_val) }; atomic_set_bit(r, index, bit); } - fn toggle_port(index: usize) { + fn toggle_pin(index: usize) { let p = Self::peripheral(); - let r: &AtomicU32 = unsafe { core::mem::transmute(&p.port) }; + let r: &AtomicU32 = unsafe { core::mem::transmute(&p.output_val) }; let mask = 1 << (index & 31); r.fetch_xor(mask, Ordering::SeqCst); } @@ -281,7 +281,7 @@ macro_rules! gpio { type Error = Infallible; fn is_high(&self) -> Result { - Ok($GPIOX::value(Self::INDEX)) + Ok($GPIOX::input_value(Self::INDEX)) } @@ -292,7 +292,7 @@ macro_rules! gpio { impl StatefulOutputPin for $PXi> { fn is_set_high(&self) -> Result { - Ok($GPIOX::value(Self::INDEX)) + Ok($GPIOX::input_value(Self::INDEX)) } fn is_set_low(&self) -> Result { @@ -304,12 +304,12 @@ macro_rules! gpio { type Error = Infallible; fn set_high(&mut self) -> Result<(), Infallible> { - $GPIOX::set_port(Self::INDEX, true); + $GPIOX::set_output_value(Self::INDEX, true); Ok(()) } fn set_low(&mut self) -> Result<(), Infallible> { - $GPIOX::set_port(Self::INDEX, false); + $GPIOX::set_output_value(Self::INDEX, false); Ok(()) } } @@ -319,7 +319,7 @@ macro_rules! gpio { /// Toggles the pin state. fn toggle(&mut self) -> Result<(), Infallible> { - $GPIOX::toggle_port(Self::INDEX); + $GPIOX::toggle_pin(Self::INDEX); Ok(()) } } From 3edab54167b825379c02c8bc22c774d345634de1 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 26 Nov 2019 10:03:06 +0300 Subject: [PATCH 216/315] Fix i2c driver --- src/i2c.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 7b27ff0..3b72be1 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -108,7 +108,7 @@ impl, PINS> I2c { fn write_cr(&self, f: F) where F: FnOnce(&mut i2c0::cr::W) -> &mut i2c0::cr::W { - self.i2c.cr_sr.write(|w| unsafe { + self.i2c.cr().write(|w| unsafe { let mut value: u32 = 0; f(mem::transmute(&mut value)); w.bits(value) @@ -117,7 +117,7 @@ impl, PINS> I2c { fn read_sr(&self) -> i2c0::sr::R { unsafe { - mem::transmute(self.i2c.cr_sr.read()) + mem::transmute(self.i2c.sr().read()) } } From a0fa7d0a5c0792d4b3253df58ebbb3f184f26e9e Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Tue, 26 Nov 2019 10:10:25 +0300 Subject: [PATCH 217/315] Do not use watermark levels in builk SPI transfers --- src/spi.rs | 76 ++++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 56 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 5bf469f..3343efd 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -26,7 +26,7 @@ use core::convert::Infallible; use core::ops::Deref; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -use crate::e310x::{QSPI0, QSPI1, QSPI2, qspi0}; +use e310x::{QSPI0, QSPI1, QSPI2, qspi0}; use crate::clock::Clocks; use crate::time::Hertz; use nb; @@ -251,18 +251,8 @@ impl embedded_hal::blocking::spi::Transfer for Spi(&mut self, words: &'w mut [u8]) -> Result<&'w[u8], Self::Error> { - // Save watermark levels - let txmark = self.spi.txmark.read().value().bits(); - let rxmark = self.spi.rxmark.read().value().bits(); - - // Set watermark levels - self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); - self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); - // Ensure that RX FIFO is empty - while self.spi.ip.read().rxwm().bit_is_set() { - let _ = self.spi.rxdata.read(); - } + while self.spi.rxdata.read().empty().bit_is_clear() { } self.cs_mode_frame(); @@ -275,19 +265,17 @@ impl embedded_hal::blocking::spi::Transfer for Spi embedded_hal::blocking::spi::Write for Spi type Error = Infallible; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - // Save watermark levels - let txmark = self.spi.txmark.read().value().bits(); - let rxmark = self.spi.rxmark.read().value().bits(); - - // Set watermark levels - self.spi.txmark.write(|w| unsafe { w.value().bits(1) }); - self.spi.rxmark.write(|w| unsafe { w.value().bits(0) }); - // Ensure that RX FIFO is empty - while self.spi.ip.read().rxwm().bit_is_set() { - let _ = self.spi.rxdata.read(); - } + while self.spi.rxdata.read().empty().bit_is_clear() { } self.cs_mode_frame(); @@ -320,18 +298,16 @@ impl embedded_hal::blocking::spi::Write for Spi self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); } - if iread < iwrite && self.spi.ip.read().rxwm().bit_is_set() { - let _ = self.spi.rxdata.read(); - iread += 1; + if iread < iwrite { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + iread += 1; + } } } self.cs_mode_word(); - // Restore watermark levels - self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); - self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); - Ok(()) } } @@ -345,18 +321,8 @@ impl embedded_hal::blocking::spi::WriteIter for Spi embedded_hal::blocking::spi::WriteIter for Spi 0 && self.spi.ip.read().rxwm().bit_is_set() { - let _ = self.spi.rxdata.read(); - read_count -= 1; + if read_count > 0 { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + read_count -= 1; + } } } self.cs_mode_word(); - // Restore watermark levels - self.spi.txmark.write(|w| unsafe { w.value().bits(txmark) }); - self.spi.rxmark.write(|w| unsafe { w.value().bits(rxmark) }); - Ok(()) } } From 6293e74b7757d43b240f5cc58feb0c772e85e97b Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 4 Feb 2020 10:10:06 -0700 Subject: [PATCH 218/315] fix overlapping clock ranges --- src/clock.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 42b6ad9..5e84097 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -222,9 +222,9 @@ impl CoreClk { // Calculate PLL R ratio let r = match pllref_freq { 24_000_000..=48_000_000 => 4, - 18_000_000..=24_000_000 => 3, - 12_000_000..=18_000_000 => 2, - 6_000_000..=12_000_000 => 1, + 18_000_000..=23_999_999 => 3, + 12_000_000..=17_999_999 => 2, + 6_000_000..=11_999_999 => 1, _ => unreachable!(), }; @@ -235,8 +235,8 @@ impl CoreClk { // Calculate PLL Q ratio let q = match pllout_freq { 192_000_000..=384_000_000 => 2, - 96_000_000..=192_000_000 => 4, - 48_000_000..=96_000_000 => 8, + 96_000_000..=191_999_999 => 4, + 48_000_000..=95_999_999 => 8, _ => unreachable!(), }; From 7e60b28b5e8599af82b0e31a4f5b7275e5609384 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Mon, 10 Feb 2020 11:21:43 +0300 Subject: [PATCH 219/315] Update e310x dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 682885f..a5ff28c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" riscv = "0.5.4" -e310x = { version = "0.7.0", features = ["rt"] } +e310x = { version = "0.8.0", features = ["rt"] } [features] g002 = ["e310x/g002"] From 694feb7668921adfc369ac382105b42f611c827a Mon Sep 17 00:00:00 2001 From: Abdelhakim Qbaich Date: Tue, 14 Apr 2020 20:07:24 -0400 Subject: [PATCH 220/315] Use the correct RTC counter register --- src/rtc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rtc.rs b/src/rtc.rs index 73216df..2c33044 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -45,12 +45,12 @@ impl Rtc { #[inline] pub fn rtc_lo(&self) -> u32 { - unsafe { (*RTC::ptr()).rtchi.read().bits() } + unsafe { (*RTC::ptr()).rtclo.read().bits() } } #[inline] pub fn rtc_hi(&self) -> u32 { - unsafe { (*RTC::ptr()).rtclo.read().bits() } + unsafe { (*RTC::ptr()).rtchi.read().bits() } } pub fn rtc(&self) -> u64 { From b892088e1483a5cf1d8c958ef93cfe3847c2ffed Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sat, 20 Jun 2020 12:48:11 +0300 Subject: [PATCH 221/315] Update embedded-hal dependency to 1.0.0-alpha.1 --- Cargo.toml | 2 +- src/delay.rs | 36 ++++++++++++++++++++++++++---------- src/gpio.rs | 20 ++++++++++---------- src/i2c.rs | 10 +++++----- src/prelude.rs | 7 +------ src/serial.rs | 6 +++--- src/spi.rs | 10 +++++----- src/stdout.rs | 4 ++-- 8 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a5ff28c..3208e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = { version = "0.2.3", features = ["unproven"] } +embedded-hal = "1.0.0-alpha.1" nb = "0.1.2" riscv = "0.5.4" e310x = { version = "0.8.0", features = ["rt"] } diff --git a/src/delay.rs b/src/delay.rs index 53b682b..77e6b35 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -4,6 +4,7 @@ use embedded_hal::blocking::delay::DelayMs; use crate::core::clint::{MTIME, MTIMECMP}; use crate::clock::Clocks; use riscv::register::{mie, mip}; +use core::convert::Infallible; /// Machine timer (mtime) as a busyloop delay provider pub struct Delay; @@ -16,24 +17,31 @@ impl Delay { } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u32) -> Result<(), Infallible> { let ticks = (ms as u64) * 32768 / 1000; let mtime = MTIME; let t = mtime.mtime() + ticks; while mtime.mtime() < t { } + Ok(()) } } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32::from(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u16) -> Result<(), Infallible> { + self.try_delay_ms(u32::from(ms)) } } impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32::from(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u8) -> Result<(), Infallible> { + self.try_delay_ms(u32::from(ms)) } } @@ -54,7 +62,9 @@ impl Sleep { } impl DelayMs for Sleep { - fn delay_ms(&mut self, ms: u32) { + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u32) -> Result<(), Infallible> { let ticks = (ms as u64) * (self.clock_freq as u64) / 1000; let t = MTIME.mtime() + ticks; @@ -84,17 +94,23 @@ impl DelayMs for Sleep { unsafe { mie::clear_mtimer(); } + + Ok(()) } } impl DelayMs for Sleep { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32::from(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u16) -> Result<(), Infallible> { + self.try_delay_ms(u32::from(ms)) } } impl DelayMs for Sleep { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32::from(ms)); + type Error = Infallible; + + fn try_delay_ms(&mut self, ms: u8) -> Result<(), Infallible> { + self.try_delay_ms(u32::from(ms)) } } diff --git a/src/gpio.rs b/src/gpio.rs index 34bf8f8..3aef68a 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -144,7 +144,7 @@ macro_rules! gpio { use core::marker::PhantomData; use core::convert::Infallible; - use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::$GPIOX; use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, @@ -280,35 +280,35 @@ macro_rules! gpio { impl InputPin for $PXi> { type Error = Infallible; - fn is_high(&self) -> Result { + fn try_is_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) } - fn is_low(&self) -> Result { - Ok(!self.is_high()?) + fn try_is_low(&self) -> Result { + Ok(!self.try_is_high()?) } } impl StatefulOutputPin for $PXi> { - fn is_set_high(&self) -> Result { + fn try_is_set_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) } - fn is_set_low(&self) -> Result { - Ok(!self.is_set_high()?) + fn try_is_set_low(&self) -> Result { + Ok(!self.try_is_set_high()?) } } impl OutputPin for $PXi> { type Error = Infallible; - fn set_high(&mut self) -> Result<(), Infallible> { + fn try_set_high(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, true); Ok(()) } - fn set_low(&mut self) -> Result<(), Infallible> { + fn try_set_low(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, false); Ok(()) } @@ -318,7 +318,7 @@ macro_rules! gpio { type Error = Infallible; /// Toggles the pin state. - fn toggle(&mut self) -> Result<(), Infallible> { + fn try_toggle(&mut self) -> Result<(), Infallible> { $GPIOX::toggle_pin(Self::INDEX); Ok(()) } diff --git a/src/i2c.rs b/src/i2c.rs index 3b72be1..77038a9 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -181,7 +181,7 @@ const FLAG_WRITE: u8 = 0; impl, PINS> Read for I2c { type Error = Error; - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { @@ -216,7 +216,7 @@ impl, PINS> Read for I2c { impl, PINS> Write for I2c { type Error = Error; - fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + fn try_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { @@ -248,7 +248,7 @@ impl, PINS> Write for I2c { impl, PINS> WriteRead for I2c { type Error = Error; - fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + fn try_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { @@ -256,9 +256,9 @@ impl, PINS> WriteRead for I2c } if !bytes.is_empty() && buffer.is_empty() { - self.write(address, bytes) + self.try_write(address, bytes) } else if !buffer.is_empty() && bytes.is_empty() { - self.read(address, buffer) + self.try_read(address, buffer) } else if bytes.is_empty() && buffer.is_empty() { Ok(()) } else { diff --git a/src/prelude.rs b/src/prelude.rs index db42b0a..6749ccc 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,12 +1,7 @@ //! Prelude pub use embedded_hal::prelude::*; -pub use embedded_hal::digital::v2::{ - InputPin as _embedded_hal_digital_v2_InputPin, - OutputPin as _embedded_hal_digital_v2_OutputPin, - StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, - ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, -}; +pub use embedded_hal::digital::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin; pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; diff --git a/src/serial.rs b/src/serial.rs index 18d0cda..0b66b99 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -118,7 +118,7 @@ impl Serial { impl serial::Read for Rx { type Error = Infallible; - fn read(&mut self) -> nb::Result { + fn try_read(&mut self) -> nb::Result { let rxdata = self.uart.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -132,7 +132,7 @@ impl serial::Read for Rx { impl serial::Write for Tx { type Error = Infallible; - fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { + fn try_write(&mut self, byte: u8) -> nb::Result<(), Infallible> { let txdata = self.uart.txdata.read(); if txdata.full().bit_is_set() { @@ -145,7 +145,7 @@ impl serial::Write for Tx { } } - fn flush(&mut self) -> nb::Result<(), Infallible> { + fn try_flush(&mut self) -> nb::Result<(), Infallible> { if self.uart.ip.read().txwm().bit_is_set() { // FIFO count is below the receive watermark (1) Ok(()) diff --git a/src/spi.rs b/src/spi.rs index 3343efd..f36a936 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -225,7 +225,7 @@ impl Spi { impl embedded_hal::spi::FullDuplex for Spi { type Error = Infallible; - fn read(&mut self) -> nb::Result { + fn try_read(&mut self) -> nb::Result { let rxdata = self.spi.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -235,7 +235,7 @@ impl embedded_hal::spi::FullDuplex for Spi { } } - fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + fn try_send(&mut self, byte: u8) -> nb::Result<(), Infallible> { let txdata = self.spi.txdata.read(); if txdata.full().bit_is_set() { @@ -250,7 +250,7 @@ impl embedded_hal::spi::FullDuplex for Spi { impl embedded_hal::blocking::spi::Transfer for Spi { type Error = Infallible; - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w[u8], Self::Error> { + fn try_transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w[u8], Self::Error> { // Ensure that RX FIFO is empty while self.spi.rxdata.read().empty().bit_is_clear() { } @@ -283,7 +283,7 @@ impl embedded_hal::blocking::spi::Transfer for Spi embedded_hal::blocking::spi::Write for Spi { type Error = Infallible; - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + fn try_write(&mut self, words: &[u8]) -> Result<(), Self::Error> { // Ensure that RX FIFO is empty while self.spi.rxdata.read().empty().bit_is_clear() { } @@ -315,7 +315,7 @@ impl embedded_hal::blocking::spi::Write for Spi impl embedded_hal::blocking::spi::WriteIter for Spi { type Error = Infallible; - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + fn try_write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator { diff --git a/src/stdout.rs b/src/stdout.rs index 57785fb..809e613 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -15,14 +15,14 @@ impl<'p, T> Write for Stdout<'p, T> fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { if *byte == b'\n' { - let res = block!(self.0.write(b'\r')); + let res = block!(self.0.try_write(b'\r')); if res.is_err() { return Err(::core::fmt::Error); } } - let res = block!(self.0.write(*byte)); + let res = block!(self.0.try_write(*byte)); if res.is_err() { return Err(::core::fmt::Error); From d2dc83c80d5fd56f9dc5760155bb140da46eedf9 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 18:29:44 +0300 Subject: [PATCH 222/315] Update riscv and e310x dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a5ff28c..fba229a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" -riscv = "0.5.4" -e310x = { version = "0.8.0", features = ["rt"] } +riscv = "0.6.0" +e310x = { version = "0.9.0", features = ["rt"] } [features] g002 = ["e310x/g002"] From 610e51c988267f0bab7c5c614ec346535dbb6b17 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 18:35:02 +0300 Subject: [PATCH 223/315] Fix SPI driver --- src/spi.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index 3343efd..ceb424f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -118,7 +118,8 @@ impl Spi { PINS: Pins { let div = clocks.tlclk().0 / (2 * freq.0) - 1; - spi.div.write(|w| unsafe { w.bits(div) }); + assert!(div <= 0xfff); + spi.sckdiv.write(|w| unsafe { w.div().bits(div as u16) }); let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { spi.csid.write(|w| unsafe { w.bits(cs_index) }); @@ -135,21 +136,21 @@ impl Spi { // Set SPI mode let phase = mode.phase == Phase::CaptureOnSecondTransition; let polarity = mode.polarity == Polarity::IdleHigh; - spi.mode.write(|w| w - .phase().bit(phase) - .polarity().bit(polarity) + spi.sckmode.write(|w| w + .pha().bit(phase) + .pol().bit(polarity) ); spi.fmt.write(|w| unsafe { w - .protocol().bits(0) // Single + .proto().bits(0) // Single .endian().clear_bit() // Transmit most-significant bit (MSB) first - .direction().rx() - .length().bits(8) + .dir().rx() + .len().bits(8) }); // Set watermark levels - spi.txmark.write(|w| unsafe { w.value().bits(1) }); - spi.rxmark.write(|w| unsafe { w.value().bits(0) }); + spi.txmark.write(|w| unsafe { w.txmark().bits(1) }); + spi.rxmark.write(|w| unsafe { w.rxmark().bits(0) }); spi.delay0.reset(); spi.delay1.reset(); @@ -159,12 +160,12 @@ impl Spi { /// Sets transmit watermark level pub fn set_tx_watermark(&mut self, value: u8) { - self.spi.txmark.write(|w| unsafe { w.value().bits(value) }); + self.spi.txmark.write(|w| unsafe { w.txmark().bits(value) }); } /// Sets receive watermark level pub fn set_rx_watermark(&mut self, value: u8) { - self.spi.rxmark.write(|w| unsafe { w.value().bits(value) }); + self.spi.rxmark.write(|w| unsafe { w.rxmark().bits(value) }); } /// Returns transmit watermark event status From 5aa6bf91991a22ff3853d220673f23c2d6b47dd3 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 18:37:59 +0300 Subject: [PATCH 224/315] Use lfrosccfg.trim() --- src/clock.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 5e84097..8265e09 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -343,9 +343,9 @@ impl AonClk { // Configure LFROSC aonclk.lfrosccfg.write(|w| { unsafe { - w.bits(trim << 16) // TODO: replace this with trim() - .div().bits(div) - .enable().bit(true) + w.trim().bits(trim); + w.div().bits(div); + w.enable().bit(true) } }); From c75697d59cea108517791f7e39154c3e6da01ba6 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 18:43:46 +0300 Subject: [PATCH 225/315] Release v0.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fba229a..2a8b276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.8.3" +version = "0.9.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 21afad3cbc95a1341507502390589dd786811ab8 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 19:22:39 +0300 Subject: [PATCH 226/315] Update riscv and e310x-hal dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3b4d39c..206d83c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.8.0" +e310x-hal = "0.9.0" embedded-hal = "0.2.3" -riscv = "0.5.3" +riscv = "0.6.0" nb = "0.1.2" [features] From f052443fcd7336871a728ba4d1dcaa72acf14136 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Nov 2020 19:27:42 +0300 Subject: [PATCH 227/315] Release v0.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 206d83c..cc0978d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.8.1" +version = "0.9.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 019ee60369cd3e471b42ea11f8789dd26119acba Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 25 Dec 2020 18:55:42 +0300 Subject: [PATCH 228/315] Implement flash configuration --- assemble.sh | 11 +++++++++++ bin/flash.a | Bin 0 -> 2222 bytes build.rs | 6 ++++++ flash.S | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/flash.rs | 21 +++++++++++++++++++++ src/lib.rs | 2 ++ 6 files changed, 85 insertions(+) create mode 100755 assemble.sh create mode 100644 bin/flash.a create mode 100644 flash.S create mode 100644 src/flash.rs diff --git a/assemble.sh b/assemble.sh new file mode 100755 index 0000000..3a04536 --- /dev/null +++ b/assemble.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -euxo pipefail + +# remove existing blobs because otherwise this will append object files to the old blobs +rm -f bin/*.a + +riscv64-unknown-elf-gcc -ggdb3 -fdebug-prefix-map=$(pwd)=/hifive1 -c -mabi=ilp32 -march=rv32imac flash.S -o bin/flash.o +riscv64-unknown-elf-ar crs bin/flash.a bin/flash.o + +rm bin/flash.o diff --git a/bin/flash.a b/bin/flash.a new file mode 100644 index 0000000000000000000000000000000000000000..4c734e21c25daa429a7aced6fcbdaeb1545f37ce GIT binary patch literal 2222 zcma)6&rcIU6n@ifD@7=U5+x#L6-A6@DGS2I5J;>hhUft`Mh~!s0!_+~Y?lU&iNup8 z9zE#IgE2jL@Fs~~JaF{D-=GJNCSFWT)bGuY?Y2PlCG+O{-n{wV%(!+*wA$x#^?q;AU6`@G2Xze*&>k9?qPvU<7iQ!4-Db2dS3wH^45 z+D`x51bxeYxsmv-d^VYkf8R~yYrBuPUPH;E6YxU(O1Hzy@>qhOjxYMEK(qgGv9Hy(+Z`o5bw(E?zoYsc+2PQ~76zws|&2-k8 z8ieypmH8?OKFfq(9dS$UdTw@woyTq-&dfQew;H}Se;KuElW!psHH&b#(ZD`DI&2X> zSTvyX>u1rdhZ}+XmT->Zoe>^F0E_rh)Xkz~Q@u1IL}Ot}T%P4Xgm(d7i0}{sSadi_ z!P}d7x`}6~M@M*%8SIyw>6{Jc#)jdCwRfrU6>~1u!4AfsH={T0Fy=+V&Z7z55R5ya zm&5l(=%uiP&91bPQyGfi^RC8$7D_5qdWfV?90xqqhWX<^a+p2;W^}X6yk12J_e* z5SxKEeeG!jJX$vc!uOWz^0ha0p8~U94vlRSq)$QVd5qgj-OC`{3j}RL(6b)fbF^sP z!AMwCdI%(U`J7)-buF1x|xns<~BCv(Vzk{P_tjF(^pE&eFTL9Vbd+`3F Nd6N*>4rkTt{sl;fv@QSu literal 0 HcmV?d00001 diff --git a/build.rs b/build.rs index a963519..0c9cc96 100644 --- a/build.rs +++ b/build.rs @@ -42,4 +42,10 @@ fn main() { } fs::copy("hifive1-link.x", out_dir.join("hifive1-link.x")).unwrap(); + + // Copy library with flash setup code + let name = env::var("CARGO_PKG_NAME").unwrap(); + fs::copy("bin/flash.a", out_dir.join(format!("lib{}.a", name))).unwrap(); + println!("cargo:rustc-link-lib=static={}", name); + println!("cargo:rerun-if-changed=bin/flash.a"); } diff --git a/flash.S b/flash.S new file mode 100644 index 0000000..53dd795 --- /dev/null +++ b/flash.S @@ -0,0 +1,45 @@ +.cfi_sections .debug_frame + +.section .data._setup_is25lp +.global _setup_is25lp +.cfi_startproc +_setup_is25lp: + li a1, 0x10014000 // QSPI0 base address + + // Disable mapped region + sw zero,96(a1) // fctrl.en = 0 + + // Construct ffmt value for 4 dummy cycles + li a2, 0x00BB1447 + + beqz a0, 2f + + // We need to set 8 dummy cycles instead of 4. + // Issue a "Set Read Parameters" command. + + li a0,2 + sw a0,24(a1) // csmode = HOLD + li a0,0xC0 + sw a0,72(a1) // txdata = 0xC0 + li a0,0xF0 + sw a0,72(a1) // txdata = 0xF0 + sw zero,24(a1) // csmode = AUTO + + // Discard two response bytes +1: lw a0,76(a1) + bltz a0,1b +1: lw a0,76(a1) + bltz a0,1b + + addi a2,a2,0x40 // ffmt: 4 -> 8 dummy cycles +2: + sw a2,100(a1) // Write ffmt + + // Enable mapped region + li a0, 1 + sw a0,96(a1) // fctrl.en = 1 + ret + + +.cfi_endproc +.size _setup_is25lp, . - _setup_is25lp diff --git a/src/flash.rs b/src/flash.rs new file mode 100644 index 0000000..cb2ab58 --- /dev/null +++ b/src/flash.rs @@ -0,0 +1,21 @@ +//! On-board SPI Flash + +use e310x_hal::e310x::QSPI0; +use e310x_hal::clock::Clocks; + +/// Configure SPI Flash interface to maximum supported speed +#[inline(always)] +pub fn configure_spi_flash(qspi: &QSPI0, clocks: &Clocks) { + unsafe { + extern "C" { + fn _setup_is25lp(dummy8: bool); + } + + if clocks.coreclk().0 <= 208_000_000 { + _setup_is25lp(false) + } else { + _setup_is25lp(true) + } + } + qspi.sckdiv.modify(|_, w| unsafe { w.div().bits(0) }); +} diff --git a/src/lib.rs b/src/lib.rs index ea37a19..f47537a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,8 @@ pub use e310x_hal as hal; pub mod clock; pub use clock::configure as configure_clocks; +pub mod flash; + #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub mod led; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] From d9413b7d430daff73eda2f91948c9913e15bc98b Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 25 Dec 2020 19:04:57 +0300 Subject: [PATCH 229/315] Provide LoFive R0 memory definitions --- build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 0c9cc96..5d647d4 100644 --- a/build.rs +++ b/build.rs @@ -32,8 +32,7 @@ fn main() { fs::copy("memory-hifive1-revb.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); } - "lofive" => {} - "lofive_r1" => { + "lofive" | "lofive_r1" => { fs::copy("memory-lofive-r1.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-lofive-r1.x"); } From 997743bd5398a27ac303eac1cd67ac019c9b3ffa Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Fri, 25 Dec 2020 19:06:23 +0300 Subject: [PATCH 230/315] Release v0.9.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cc0978d..7832ecf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.9.0" +version = "0.9.1" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 5d2e137f4c44b0528e269228113f27193652ed33 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 10 Jul 2021 22:34:01 -0700 Subject: [PATCH 231/315] update nb dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2a8b276..383ac72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } -nb = "0.1.2" +nb = "1.0.0" riscv = "0.6.0" e310x = { version = "0.9.0", features = ["rt"] } From 320995418bd79c9b2e9f72cbc1eb4da400752cef Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 10 Jul 2021 22:38:09 -0700 Subject: [PATCH 232/315] implement DelayUs for Delay --- src/delay.rs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index 53b682b..0df06ac 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,13 +1,15 @@ //! # Delays -use embedded_hal::blocking::delay::DelayMs; -use crate::core::clint::{MTIME, MTIMECMP}; use crate::clock::Clocks; +use crate::core::clint::{MTIME, MTIMECMP}; +use embedded_hal::blocking::delay::{DelayMs, DelayUs}; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider pub struct Delay; +const TICKS_PER_SECOND: u64 = 32768; + impl Delay { /// Constructs a delay provider based on the machine timer (mtime) pub fn new() -> Self { @@ -15,13 +17,31 @@ impl Delay { } } -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { - let ticks = (ms as u64) * 32768 / 1000; +impl DelayUs for Delay { + fn delay_us(&mut self, us: u32) { + let ticks = (us as u64) * TICKS_PER_SECOND / 1000_0000; let mtime = MTIME; let t = mtime.mtime() + ticks; - while mtime.mtime() < t { } + while mtime.mtime() < t {} + } +} + +impl DelayUs for Delay { + fn delay_us(&mut self, us: u16) { + self.delay_ms(u32::from(us)); + } +} + +impl DelayUs for Delay { + fn delay_us(&mut self, us: u8) { + self.delay_ms(u32::from(us)); + } +} + +impl DelayMs for Delay { + fn delay_ms(&mut self, ms: u32) { + self.delay_us(ms * 1000); } } @@ -40,7 +60,7 @@ impl DelayMs for Delay { /// Machine timer (mtime) as a sleep delay provider using mtimecmp pub struct Sleep { clock_freq: u32, - mtimecmp: MTIMECMP + mtimecmp: MTIMECMP, } impl Sleep { @@ -64,7 +84,7 @@ impl DelayMs for Sleep { unsafe { mie::set_mtimer(); } - + // Wait For Interrupt will put CPU to sleep until an interrupt hits // in our case when internal timer mtime value >= mtimecmp value // after which empty handler gets called and we go into the From dab45aec725596c7fd755a5b6aa9030d2002c4e3 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Wed, 14 Jul 2021 11:12:40 -0700 Subject: [PATCH 233/315] add SparkFun RED-V board support --- Cargo.toml | 1 + README.md | 8 +++++++ build.rs | 2 +- ci/script.sh | 1 + src/clock.rs | 2 +- src/gpio.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/led.rs | 18 +++++++++++++++ src/lib.rs | 4 +++- 8 files changed, 96 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7832ecf..514a62b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ nb = "0.1.2" [features] board-hifive1 = [] board-hifive1-revb = ["e310x-hal/g002"] +board-redv = ["e310x-hal/g002"] board-lofive = [] board-lofive-r1 = ["e310x-hal/g002"] diff --git a/README.md b/README.md index 3c9dfd0..c087cf0 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@ > Board support crate for HiFive1 and LoFive boards +## Supported Boards + +`hifive1` - use feature `board-hifive1` +`hifive1-revb` - use feature `board-hifive1-revb` +`redv` - use feature `board-redv` +`lofive` - use feature `board-lofive` +`lofive-r1` - use feature `board-lofive-r1` + ## [Documentation](https://docs.rs/crate/hifive1) ## License diff --git a/build.rs b/build.rs index 5d647d4..657ae69 100644 --- a/build.rs +++ b/build.rs @@ -28,7 +28,7 @@ fn main() { fs::copy("memory-hifive1.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1.x"); } - "hifive1_revb" => { + "hifive1_revb" | "redv" => { fs::copy("memory-hifive1-revb.x", out_dir.join("hifive1-memory.x")).unwrap(); println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); } diff --git a/ci/script.sh b/ci/script.sh index 0dd41cd..c5bc32b 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -4,5 +4,6 @@ set -euxo pipefail cargo check --target $TARGET --features 'board-hifive1' cargo check --target $TARGET --features 'board-hifive1-revb' +cargo check --target $TARGET --features 'board-redv' cargo check --target $TARGET --features 'board-lofive' cargo check --target $TARGET --features 'board-lofive-r1' diff --git a/src/clock.rs b/src/clock.rs index 3081152..650bad1 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -6,7 +6,7 @@ use e310x_hal::{ time::Hertz, }; -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-redv"))] /// Configures clock generation system. /// /// For HiFive1 and HiFive1 Rev B boards external oscillators are enabled for diff --git a/src/gpio.rs b/src/gpio.rs index 7a3d247..1a12521 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,3 +1,4 @@ +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// /// Returns single pin for given gpio object mapped accordingly /// @@ -58,7 +59,69 @@ macro_rules! pin { ($gpio:ident, led_red) => { $gpio.pin22 }; ($gpio:ident, led_green) => { $gpio.pin19 }; ($gpio:ident, led_blue) => { $gpio.pin21 }; + // #[cfg(feature = "redv")] + // ($gpio:ident, led_blue) => { $gpio.pin4 }; +} +#[cfg(feature = "board-redv")] +/// +/// Returns single pin for given gpio object mapped accordingly +/// +/// # Mappings +/// +/// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) +/// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) +/// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) +/// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 +/// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) +/// +/// # Example +/// +/// ``` +/// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 +/// ``` +/// +#[macro_export] +macro_rules! pin { + // empty + ($gpio:ident, none) => { () }; + // spi + ($gpio:ident, spi0_sck) => { $gpio.pin5 }; + ($gpio:ident, spi0_mosi) => { $gpio.pin3 }; + ($gpio:ident, spi0_miso) => { $gpio.pin4 }; + ($gpio:ident, spi0_ss0) => { $gpio.pin2 }; + // spi_ss1 is not documented + ($gpio:ident, spi0_ss2) => { $gpio.pin9 }; + ($gpio:ident, spi0_ss3) => { $gpio.pin10 }; + // i2c + ($gpio:ident, i2c0_sda) => { $gpio.pin12 }; + ($gpio:ident, i2c0_scl) => { $gpio.pin13 }; + // serial + ($gpio:ident, uart0_tx) => { $gpio.pin17 }; + ($gpio:ident, uart0_rx) => { $gpio.pin16 }; + // digital/physical + ($gpio:ident, dig0) => { $gpio.pin16 }; + ($gpio:ident, dig1) => { $gpio.pin17 }; + ($gpio:ident, dig2) => { $gpio.pin18 }; + ($gpio:ident, dig3) => { $gpio.pin19 }; + ($gpio:ident, dig4) => { $gpio.pin20 }; + ($gpio:ident, dig5) => { $gpio.pin21 }; + ($gpio:ident, dig6) => { $gpio.pin22 }; + ($gpio:ident, dig7) => { $gpio.pin23 }; + ($gpio:ident, dig8) => { $gpio.pin0 }; + ($gpio:ident, dig9) => { $gpio.pin1 }; + ($gpio:ident, dig10) => { $gpio.pin2 }; + ($gpio:ident, dig11) => { $gpio.pin3 }; + ($gpio:ident, dig12) => { $gpio.pin4 }; + ($gpio:ident, dig13) => { $gpio.pin5 }; + ($gpio:ident, dig14) => { $gpio.pin8 }; // tested + ($gpio:ident, dig15) => { $gpio.pin9 }; + ($gpio:ident, dig16) => { $gpio.pin10 }; + ($gpio:ident, dig17) => { $gpio.pin11 }; + ($gpio:ident, dig18) => { $gpio.pin12 }; + ($gpio:ident, dig19) => { $gpio.pin13 }; + // onboard LEDs + ($gpio:ident, led_blue) => { $gpio.pin4 }; } /// diff --git a/src/led.rs b/src/led.rs index 9686f5d..e85380f 100644 --- a/src/led.rs +++ b/src/led.rs @@ -1,21 +1,37 @@ //! On-board user LEDs //! +//! Hifive1 (+ revB) //! - Red = Pin 22 //! - Green = Pin 19 //! - Blue = Pin 21 +//! +//! RedV +//! - Blue = Pin 4 + use embedded_hal::digital::v2::OutputPin; +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22}; +#[cfg(feature = "board-redv")] +use e310x_hal::gpio::gpio0::{Pin4}; use e310x_hal::gpio::{Output, Regular, Invert}; +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Red LED pub type RED = Pin22>>; +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Green LED pub type GREEN = Pin19>>; +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Blue LED pub type BLUE = Pin21>>; +#[cfg(feature = "board-redv")] +/// Blue LED +pub type BLUE = Pin4>>; + +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Returns RED, GREEN and BLUE LEDs. pub fn rgb( red: Pin22, green: Pin19, blue: Pin21 @@ -36,6 +52,7 @@ pub trait Led { fn on(&mut self); } +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] impl Led for RED { fn off(&mut self) { self.set_low().unwrap(); @@ -46,6 +63,7 @@ impl Led for RED { } } +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] impl Led for GREEN { fn off(&mut self) { self.set_low().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index f47537a..59f9e1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,12 @@ pub use clock::configure as configure_clocks; pub mod flash; -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-redv"))] pub mod led; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] pub use led::{RED, GREEN, BLUE, rgb, Led}; +#[cfg(feature = "board-redv")] +pub use led::{BLUE, Led}; pub mod stdout; pub use stdout::configure as configure_stdout; From 5aca858d892ffabb116912edda44db851533125b Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Wed, 14 Jul 2021 11:14:14 -0700 Subject: [PATCH 234/315] remove unused comment --- src/gpio.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 1a12521..39a2ef4 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -59,8 +59,6 @@ macro_rules! pin { ($gpio:ident, led_red) => { $gpio.pin22 }; ($gpio:ident, led_green) => { $gpio.pin19 }; ($gpio:ident, led_blue) => { $gpio.pin21 }; - // #[cfg(feature = "redv")] - // ($gpio:ident, led_blue) => { $gpio.pin4 }; } #[cfg(feature = "board-redv")] From 7a66069eaa8b6eeedec7e621ececa1188b87c95e Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Wed, 14 Jul 2021 11:24:04 -0700 Subject: [PATCH 235/315] fix Pin4 -> Pin5 typo + fmt --- build.rs | 18 ++-- src/clock.rs | 18 +++- src/flash.rs | 2 +- src/gpio.rs | 294 ++++++++++++++++++++++++++++++++++++-------------- src/led.rs | 17 ++- src/lib.rs | 10 +- src/stdout.rs | 27 +++-- 7 files changed, 264 insertions(+), 122 deletions(-) diff --git a/build.rs b/build.rs index 657ae69..e731326 100644 --- a/build.rs +++ b/build.rs @@ -1,18 +1,20 @@ -use std::{env, fs}; use std::path::PathBuf; +use std::{env, fs}; fn main() { // Put the memory definitions somewhere the linker can find it let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out_dir.display()); - let boards: Vec<_> = env::vars().filter_map(|(key, _value)| { - if key.starts_with("CARGO_FEATURE_BOARD") { - Some(key[20..].to_ascii_lowercase()) // Strip 'CARGO_FEATURE_BOARD_' - } else { - None - } - }).collect(); + let boards: Vec<_> = env::vars() + .filter_map(|(key, _value)| { + if key.starts_with("CARGO_FEATURE_BOARD") { + Some(key[20..].to_ascii_lowercase()) // Strip 'CARGO_FEATURE_BOARD_' + } else { + None + } + }) + .collect(); if boards.is_empty() { panic!("No board features selected"); diff --git a/src/clock.rs b/src/clock.rs index 650bad1..05bd348 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,19 +1,25 @@ //! Board-specific clock configuration use e310x_hal::{ - e310x::{PRCI, AONCLK}, - clock::{Clocks, PrciExt, AonExt}, + clock::{AonExt, Clocks, PrciExt}, + e310x::{AONCLK, PRCI}, time::Hertz, }; -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-redv"))] +#[cfg(any( + feature = "board-hifive1", + feature = "board-hifive1-revb", + feature = "board-redv" +))] /// Configures clock generation system. /// /// For HiFive1 and HiFive1 Rev B boards external oscillators are enabled for /// both high-frequency and low-frequency clocks. pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); - let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); + let coreclk = coreclk + .use_external(Hertz(16_000_000)) + .coreclk(target_coreclk); let aonclk = aonclk.constrain(); let aonclk = aonclk.use_external(Hertz(32_768)); @@ -28,7 +34,9 @@ pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { /// high-frequency clock. For low-frequency clock internal oscillator is used. pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); - let coreclk = coreclk.use_external(Hertz(16_000_000)).coreclk(target_coreclk); + let coreclk = coreclk + .use_external(Hertz(16_000_000)) + .coreclk(target_coreclk); let aonclk = aonclk.constrain(); diff --git a/src/flash.rs b/src/flash.rs index cb2ab58..e138c99 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -1,7 +1,7 @@ //! On-board SPI Flash -use e310x_hal::e310x::QSPI0; use e310x_hal::clock::Clocks; +use e310x_hal::e310x::QSPI0; /// Configure SPI Flash interface to maximum supported speed #[inline(always)] diff --git a/src/gpio.rs b/src/gpio.rs index 39a2ef4..4ba26e8 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,146 +1,278 @@ #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// /// Returns single pin for given gpio object mapped accordingly -/// +/// /// # Mappings -/// +/// /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) -/// +/// /// # Example -/// +/// /// ``` /// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 /// ``` -/// +/// #[macro_export] macro_rules! pin { // empty - ($gpio:ident, none) => { () }; + ($gpio:ident, none) => { + () + }; // spi - ($gpio:ident, spi0_sck) => { $gpio.pin5 }; - ($gpio:ident, spi0_mosi) => { $gpio.pin3 }; - ($gpio:ident, spi0_miso) => { $gpio.pin4 }; - ($gpio:ident, spi0_ss0) => { $gpio.pin2 }; + ($gpio:ident, spi0_sck) => { + $gpio.pin5 + }; + ($gpio:ident, spi0_mosi) => { + $gpio.pin3 + }; + ($gpio:ident, spi0_miso) => { + $gpio.pin4 + }; + ($gpio:ident, spi0_ss0) => { + $gpio.pin2 + }; // spi_ss1 is not documented - ($gpio:ident, spi0_ss2) => { $gpio.pin9 }; - ($gpio:ident, spi0_ss3) => { $gpio.pin10 }; + ($gpio:ident, spi0_ss2) => { + $gpio.pin9 + }; + ($gpio:ident, spi0_ss3) => { + $gpio.pin10 + }; // i2c - ($gpio:ident, i2c0_sda) => { $gpio.pin12 }; - ($gpio:ident, i2c0_scl) => { $gpio.pin13 }; + ($gpio:ident, i2c0_sda) => { + $gpio.pin12 + }; + ($gpio:ident, i2c0_scl) => { + $gpio.pin13 + }; // serial - ($gpio:ident, uart0_tx) => { $gpio.pin17 }; - ($gpio:ident, uart0_rx) => { $gpio.pin16 }; + ($gpio:ident, uart0_tx) => { + $gpio.pin17 + }; + ($gpio:ident, uart0_rx) => { + $gpio.pin16 + }; // digital/physical - ($gpio:ident, dig0) => { $gpio.pin16 }; - ($gpio:ident, dig1) => { $gpio.pin17 }; - ($gpio:ident, dig2) => { $gpio.pin18 }; - ($gpio:ident, dig3) => { $gpio.pin19 }; - ($gpio:ident, dig4) => { $gpio.pin20 }; - ($gpio:ident, dig5) => { $gpio.pin21 }; - ($gpio:ident, dig6) => { $gpio.pin22 }; - ($gpio:ident, dig7) => { $gpio.pin23 }; - ($gpio:ident, dig8) => { $gpio.pin0 }; - ($gpio:ident, dig9) => { $gpio.pin1 }; - ($gpio:ident, dig10) => { $gpio.pin2 }; - ($gpio:ident, dig11) => { $gpio.pin3 }; - ($gpio:ident, dig12) => { $gpio.pin4 }; - ($gpio:ident, dig13) => { $gpio.pin5 }; - ($gpio:ident, dig14) => { $gpio.pin8 }; // tested - ($gpio:ident, dig15) => { $gpio.pin9 }; - ($gpio:ident, dig16) => { $gpio.pin10 }; - ($gpio:ident, dig17) => { $gpio.pin11 }; - ($gpio:ident, dig18) => { $gpio.pin12 }; - ($gpio:ident, dig19) => { $gpio.pin13 }; + ($gpio:ident, dig0) => { + $gpio.pin16 + }; + ($gpio:ident, dig1) => { + $gpio.pin17 + }; + ($gpio:ident, dig2) => { + $gpio.pin18 + }; + ($gpio:ident, dig3) => { + $gpio.pin19 + }; + ($gpio:ident, dig4) => { + $gpio.pin20 + }; + ($gpio:ident, dig5) => { + $gpio.pin21 + }; + ($gpio:ident, dig6) => { + $gpio.pin22 + }; + ($gpio:ident, dig7) => { + $gpio.pin23 + }; + ($gpio:ident, dig8) => { + $gpio.pin0 + }; + ($gpio:ident, dig9) => { + $gpio.pin1 + }; + ($gpio:ident, dig10) => { + $gpio.pin2 + }; + ($gpio:ident, dig11) => { + $gpio.pin3 + }; + ($gpio:ident, dig12) => { + $gpio.pin4 + }; + ($gpio:ident, dig13) => { + $gpio.pin5 + }; + ($gpio:ident, dig14) => { + $gpio.pin8 + }; // tested + ($gpio:ident, dig15) => { + $gpio.pin9 + }; + ($gpio:ident, dig16) => { + $gpio.pin10 + }; + ($gpio:ident, dig17) => { + $gpio.pin11 + }; + ($gpio:ident, dig18) => { + $gpio.pin12 + }; + ($gpio:ident, dig19) => { + $gpio.pin13 + }; // onboard LEDs - ($gpio:ident, led_red) => { $gpio.pin22 }; - ($gpio:ident, led_green) => { $gpio.pin19 }; - ($gpio:ident, led_blue) => { $gpio.pin21 }; + ($gpio:ident, led_red) => { + $gpio.pin22 + }; + ($gpio:ident, led_green) => { + $gpio.pin19 + }; + ($gpio:ident, led_blue) => { + $gpio.pin21 + }; } #[cfg(feature = "board-redv")] /// /// Returns single pin for given gpio object mapped accordingly -/// +/// /// # Mappings -/// +/// /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) -/// +/// /// # Example -/// +/// /// ``` /// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 /// ``` -/// +/// #[macro_export] macro_rules! pin { // empty - ($gpio:ident, none) => { () }; + ($gpio:ident, none) => { + () + }; // spi - ($gpio:ident, spi0_sck) => { $gpio.pin5 }; - ($gpio:ident, spi0_mosi) => { $gpio.pin3 }; - ($gpio:ident, spi0_miso) => { $gpio.pin4 }; - ($gpio:ident, spi0_ss0) => { $gpio.pin2 }; + ($gpio:ident, spi0_sck) => { + $gpio.pin5 + }; + ($gpio:ident, spi0_mosi) => { + $gpio.pin3 + }; + ($gpio:ident, spi0_miso) => { + $gpio.pin4 + }; + ($gpio:ident, spi0_ss0) => { + $gpio.pin2 + }; // spi_ss1 is not documented - ($gpio:ident, spi0_ss2) => { $gpio.pin9 }; - ($gpio:ident, spi0_ss3) => { $gpio.pin10 }; + ($gpio:ident, spi0_ss2) => { + $gpio.pin9 + }; + ($gpio:ident, spi0_ss3) => { + $gpio.pin10 + }; // i2c - ($gpio:ident, i2c0_sda) => { $gpio.pin12 }; - ($gpio:ident, i2c0_scl) => { $gpio.pin13 }; + ($gpio:ident, i2c0_sda) => { + $gpio.pin12 + }; + ($gpio:ident, i2c0_scl) => { + $gpio.pin13 + }; // serial - ($gpio:ident, uart0_tx) => { $gpio.pin17 }; - ($gpio:ident, uart0_rx) => { $gpio.pin16 }; + ($gpio:ident, uart0_tx) => { + $gpio.pin17 + }; + ($gpio:ident, uart0_rx) => { + $gpio.pin16 + }; // digital/physical - ($gpio:ident, dig0) => { $gpio.pin16 }; - ($gpio:ident, dig1) => { $gpio.pin17 }; - ($gpio:ident, dig2) => { $gpio.pin18 }; - ($gpio:ident, dig3) => { $gpio.pin19 }; - ($gpio:ident, dig4) => { $gpio.pin20 }; - ($gpio:ident, dig5) => { $gpio.pin21 }; - ($gpio:ident, dig6) => { $gpio.pin22 }; - ($gpio:ident, dig7) => { $gpio.pin23 }; - ($gpio:ident, dig8) => { $gpio.pin0 }; - ($gpio:ident, dig9) => { $gpio.pin1 }; - ($gpio:ident, dig10) => { $gpio.pin2 }; - ($gpio:ident, dig11) => { $gpio.pin3 }; - ($gpio:ident, dig12) => { $gpio.pin4 }; - ($gpio:ident, dig13) => { $gpio.pin5 }; - ($gpio:ident, dig14) => { $gpio.pin8 }; // tested - ($gpio:ident, dig15) => { $gpio.pin9 }; - ($gpio:ident, dig16) => { $gpio.pin10 }; - ($gpio:ident, dig17) => { $gpio.pin11 }; - ($gpio:ident, dig18) => { $gpio.pin12 }; - ($gpio:ident, dig19) => { $gpio.pin13 }; + ($gpio:ident, dig0) => { + $gpio.pin16 + }; + ($gpio:ident, dig1) => { + $gpio.pin17 + }; + ($gpio:ident, dig2) => { + $gpio.pin18 + }; + ($gpio:ident, dig3) => { + $gpio.pin19 + }; + ($gpio:ident, dig4) => { + $gpio.pin20 + }; + ($gpio:ident, dig5) => { + $gpio.pin21 + }; + ($gpio:ident, dig6) => { + $gpio.pin22 + }; + ($gpio:ident, dig7) => { + $gpio.pin23 + }; + ($gpio:ident, dig8) => { + $gpio.pin0 + }; + ($gpio:ident, dig9) => { + $gpio.pin1 + }; + ($gpio:ident, dig10) => { + $gpio.pin2 + }; + ($gpio:ident, dig11) => { + $gpio.pin3 + }; + ($gpio:ident, dig12) => { + $gpio.pin4 + }; + ($gpio:ident, dig13) => { + $gpio.pin5 + }; + ($gpio:ident, dig14) => { + $gpio.pin8 + }; // tested + ($gpio:ident, dig15) => { + $gpio.pin9 + }; + ($gpio:ident, dig16) => { + $gpio.pin10 + }; + ($gpio:ident, dig17) => { + $gpio.pin11 + }; + ($gpio:ident, dig18) => { + $gpio.pin12 + }; + ($gpio:ident, dig19) => { + $gpio.pin13 + }; // onboard LEDs - ($gpio:ident, led_blue) => { $gpio.pin4 }; + ($gpio:ident, led_blue) => { + $gpio.pin5 + }; } /// /// Returns tuple of pins for given gpio object mapped accordingly -/// +/// /// # Mappings -/// +/// /// - `none` — Returns `()` for empty pin if needed in tuple /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 /// - `led_` - Internal LED light pins `` is one of (`red`, `green`, `blue`) -/// +/// /// # Example -/// +/// /// ``` /// let (mosi, miso, sck, cs) = pins!(gpio, (spi0_mosi, spi0_miso, spi0_sck, spi0_ss0)); /// // (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2) /// ``` -/// +/// #[macro_export] macro_rules! pins { ( $gpio:ident, ($($name:ident),+) ) => { diff --git a/src/led.rs b/src/led.rs index e85380f..d2c1b27 100644 --- a/src/led.rs +++ b/src/led.rs @@ -6,14 +6,14 @@ //! - Blue = Pin 21 //! //! RedV -//! - Blue = Pin 4 +//! - Blue = Pin 5 -use embedded_hal::digital::v2::OutputPin; +#[cfg(feature = "board-redv")] +use e310x_hal::gpio::gpio0::Pin5; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22}; -#[cfg(feature = "board-redv")] -use e310x_hal::gpio::gpio0::{Pin4}; -use e310x_hal::gpio::{Output, Regular, Invert}; +use e310x_hal::gpio::{Invert, Output, Regular}; +use embedded_hal::digital::v2::OutputPin; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Red LED @@ -29,14 +29,11 @@ pub type BLUE = Pin21>>; #[cfg(feature = "board-redv")] /// Blue LED -pub type BLUE = Pin4>>; +pub type BLUE = Pin5>>; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Returns RED, GREEN and BLUE LEDs. -pub fn rgb( - red: Pin22, green: Pin19, blue: Pin21 -) -> (RED, GREEN, BLUE) -{ +pub fn rgb(red: Pin22, green: Pin19, blue: Pin21) -> (RED, GREEN, BLUE) { let red: RED = red.into_inverted_output(); let green: GREEN = green.into_inverted_output(); let blue: BLUE = blue.into_inverted_output(); diff --git a/src/lib.rs b/src/lib.rs index 59f9e1f..9ed422b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,16 @@ pub use clock::configure as configure_clocks; pub mod flash; -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb", feature = "board-redv"))] +#[cfg(any( + feature = "board-hifive1", + feature = "board-hifive1-revb", + feature = "board-redv" +))] pub mod led; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] -pub use led::{RED, GREEN, BLUE, rgb, Led}; +pub use led::{rgb, Led, BLUE, GREEN, RED}; #[cfg(feature = "board-redv")] -pub use led::{BLUE, Led}; +pub use led::{Led, BLUE}; pub mod stdout; pub use stdout::configure as configure_stdout; diff --git a/src/stdout.rs b/src/stdout.rs index 2626773..e683f36 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -1,21 +1,19 @@ //! Stdout based on the UART hooked up to FTDI or J-Link use core::fmt; -use nb::block; -use riscv::interrupt; use e310x_hal::{ - serial::{Serial, Tx, Rx}, - gpio::gpio0::{Pin17, Pin16}, - time::Bps, clock::Clocks, e310x::UART0, - prelude::* + gpio::gpio0::{Pin16, Pin17}, + prelude::*, + serial::{Rx, Serial, Tx}, + time::Bps, }; - +use nb::block; +use riscv::interrupt; static mut STDOUT: Option = None; - struct SerialWrapper(Tx); impl core::fmt::Write for SerialWrapper { @@ -41,18 +39,19 @@ impl core::fmt::Write for SerialWrapper { /// Configures stdout pub fn configure( - uart: UART0, tx: Pin17, rx: Pin16, - baud_rate: Bps, clocks: Clocks + uart: UART0, + tx: Pin17, + rx: Pin16, + baud_rate: Bps, + clocks: Clocks, ) -> Rx { let tx = tx.into_iof0(); let rx = rx.into_iof0(); let serial = Serial::new(uart, (tx, rx), baud_rate, clocks); let (tx, rx) = serial.split(); - interrupt::free(|_| { - unsafe { - STDOUT.replace(SerialWrapper(tx)); - } + interrupt::free(|_| unsafe { + STDOUT.replace(SerialWrapper(tx)); }); return rx; } From e5daaee8cd326b65488ccebb797723680cd30837 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 09:53:16 -0700 Subject: [PATCH 236/315] fix formatting --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c087cf0..dc0fe8d 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ ## Supported Boards -`hifive1` - use feature `board-hifive1` -`hifive1-revb` - use feature `board-hifive1-revb` -`redv` - use feature `board-redv` -`lofive` - use feature `board-lofive` -`lofive-r1` - use feature `board-lofive-r1` +* `hifive1` - use feature `board-hifive1` +* `hifive1-revb` - use feature `board-hifive1-revb` +* `redv` - use feature `board-redv` +* `lofive` - use feature `board-lofive` +* `lofive-r1` - use feature `board-lofive-r1` ## [Documentation](https://docs.rs/crate/hifive1) From ef0d173a04d8af490caf8869d50a1706f4ef52d6 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 09:53:26 -0700 Subject: [PATCH 237/315] update nb to v1.0.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 514a62b..b0976fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" e310x-hal = "0.9.0" embedded-hal = "0.2.3" riscv = "0.6.0" -nb = "0.1.2" +nb = "1.0.0" [features] board-hifive1 = [] From ba4fd96caaeb34b0b8d0c33430bd1c4d15b403a5 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 10:35:23 -0700 Subject: [PATCH 238/315] use full board names with links --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dc0fe8d..a16a2e4 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ ## Supported Boards -* `hifive1` - use feature `board-hifive1` -* `hifive1-revb` - use feature `board-hifive1-revb` -* `redv` - use feature `board-redv` -* `lofive` - use feature `board-lofive` -* `lofive-r1` - use feature `board-lofive-r1` +* [SiFive Hifive1](https://www.sifive.com/boards/hifive1) - use feature `board-hifive1` +* [SiFive Hifive1 RevB](https://www.sifive.com/boards/hifive1-rev-b) - use feature `board-hifive1-revb` +* [SparkFun Red-V RedBoard](https://www.sparkfun.com/products/15594) - use feature `board-redv` +* [lofive1](https://github.com/mwelling/lofive) - use feature `board-lofive` +* [lofive1-r1](https://github.com/mwelling/lofive) - use feature `board-lofive-r1` ## [Documentation](https://docs.rs/crate/hifive1) From 08823e9416fab26bb34c76f48db49ce4818a9a7c Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:11:16 -0700 Subject: [PATCH 239/315] add CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..eba48f8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.9.1] - 2021-07-15 + +### Added + +- Added implementation of `embedded_hal::blocking::delay::DelayUs` for `e310x-hal::delay::Delay` using `MTIME` From c622ce689f1748052716e4f246fe722c19e699b5 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:11:26 -0700 Subject: [PATCH 240/315] bump version to v0.9.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 383ac72..36e72d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.0" +version = "0.9.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 46f2222a28ea80aca9a4103c10cce6e715d28178 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:22:24 -0700 Subject: [PATCH 241/315] update dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b0976fc..9a1aad2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.9.0" -embedded-hal = "0.2.3" +e310x-hal = "0.9.1" +embedded-hal = "0.2.5" riscv = "0.6.0" nb = "1.0.0" From f0675d387b839c4b61019c7498e0e91ef713ef35 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:22:33 -0700 Subject: [PATCH 242/315] bump version to v0.9.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9a1aad2..d2da503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.9.1" +version = "0.9.2" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From fcc3f79fc6ab511604fffa9b434e3392aaabf648 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:25:51 -0700 Subject: [PATCH 243/315] add CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4df48f2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +## [v0.10.0] - 2021-07-15 + +### Added + +- Added [SparkFun Red-V RedBoard](https://www.sparkfun.com/products/15594)` support From 4a81fd8015d21ebde7d9eea4a14b251cb59d78c2 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 15 Jul 2021 16:25:59 -0700 Subject: [PATCH 244/315] use v0.10.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d2da503..601da86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.9.2" +version = "0.10.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 5e017f21ac44050d9effbc319b7412f3e543d187 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 17 Jul 2021 13:35:22 -0700 Subject: [PATCH 245/315] fix typo in delay extra 0 --- src/delay.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/delay.rs b/src/delay.rs index 0df06ac..297620d 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -19,7 +19,7 @@ impl Delay { impl DelayUs for Delay { fn delay_us(&mut self, us: u32) { - let ticks = (us as u64) * TICKS_PER_SECOND / 1000_0000; + let ticks = (us as u64) * TICKS_PER_SECOND / 1000_000; let mtime = MTIME; let t = mtime.mtime() + ticks; From 856991c86d713f16d97d1891e2be0277d3bb4d2f Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 17 Jul 2021 13:39:08 -0700 Subject: [PATCH 246/315] cargo fmt --- src/clock.rs | 71 +++++++++------------ src/core/clint.rs | 14 ++--- src/core/counters.rs | 5 +- src/core/mod.rs | 2 +- src/core/plic.rs | 30 +++------ src/gpio.rs | 2 - src/i2c.rs | 54 +++++++++------- src/lib.rs | 6 +- src/pmu.rs | 66 +++++++++---------- src/prelude.rs | 15 +++-- src/serial.rs | 23 ++++--- src/spi.rs | 146 +++++++++++++++++++++++++++---------------- src/stdout.rs | 4 +- src/wdog.rs | 18 ++++-- 14 files changed, 241 insertions(+), 215 deletions(-) diff --git a/src/clock.rs b/src/clock.rs index 8265e09..2d8908b 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,10 +1,9 @@ //! Clock configuration -use e310x::{PRCI, AONCLK}; use crate::core::clint::MTIME; +use crate::time::Hertz; +use e310x::{AONCLK, PRCI}; use riscv::interrupt; use riscv::register::mcycle; -use crate::time::Hertz; - const PLLREF_MIN: u32 = 6_000_000; const PLLREF_MAX: u32 = 48_000_000; @@ -17,7 +16,6 @@ const PLLOUT_MAX: u32 = 384_000_000; const DIVOUT_MIN: u32 = 375_000; const DIVOUT_MAX: u32 = 384_000_000; - /// PrciExt trait extends `PRCI` peripheral. pub trait PrciExt { /// Constrains the `PRCI` peripheral so it plays nicely with the other @@ -43,9 +41,7 @@ impl PrciExt for PRCI { impl AonExt for AONCLK { fn constrain(self) -> AonClk { - AonClk { - lfaltclk: None, - } + AonClk { lfaltclk: None } } } @@ -79,10 +75,8 @@ impl CoreClk { let prci = unsafe { &*PRCI::ptr() }; let hfrosc_freq = self.configure_hfrosc(); // Switch to HFROSC, bypass PLL - prci.pllcfg.modify(|_, w| w - .sel().bit(false) - .bypass().bit(true) - ); + prci.pllcfg + .modify(|_, w| w.sel().bit(false).bypass().bit(true)); if let Some(freq) = self.hfxosc { self.configure_with_external(freq) @@ -140,10 +134,8 @@ impl CoreClk { freq = hfrosc_freq; // Switch to HFROSC, bypass PLL to save power - prci.pllcfg.modify(|_, w| w - .sel().bit(false) - .bypass().bit(true) - ); + prci.pllcfg + .modify(|_, w| w.sel().bit(false).bypass().bit(true)); // prci.pllcfg.modify(|_, w| w.bypass().bit(true)); @@ -155,7 +147,6 @@ impl CoreClk { // Switch to PLL prci.pllcfg.modify(|_, w| w.sel().bit(true)); - } // Disable HFXOSC to save power @@ -171,11 +162,8 @@ impl CoreClk { // TODO: use trim value from OTP // Configure HFROSC to 13.8 MHz - prci.hfrosccfg.write(|w| unsafe { w - .div().bits(4) - .trim().bits(16) - .enable().bit(true) - }); + prci.hfrosccfg + .write(|w| unsafe { w.div().bits(4).trim().bits(16).enable().bit(true) }); // Wait for HFROSC to stabilize while !prci.hfrosccfg.read().ready().bit_is_set() {} @@ -224,7 +212,7 @@ impl CoreClk { 24_000_000..=48_000_000 => 4, 18_000_000..=23_999_999 => 3, 12_000_000..=17_999_999 => 2, - 6_000_000..=11_999_999 => 1, + 6_000_000..=11_999_999 => 1, _ => unreachable!(), }; @@ -235,8 +223,8 @@ impl CoreClk { // Calculate PLL Q ratio let q = match pllout_freq { 192_000_000..=384_000_000 => 2, - 96_000_000..=191_999_999 => 4, - 48_000_000..=95_999_999 => 8, + 96_000_000..=191_999_999 => 4, + 48_000_000..=95_999_999 => 8, _ => unreachable!(), }; @@ -253,7 +241,10 @@ impl CoreClk { let vco_lo = refr_freq * f_lo; let f_hi = f_lo + 2; let vco_hi = refr_freq * f_hi; - let (f, vco_freq) = if (f_hi <= 128 && vco_hi <= VCO_MAX) && (target_vco_freq as i32 - vco_hi as i32).abs() < (target_vco_freq as i32 - vco_lo as i32).abs() { + let (f, vco_freq) = if (f_hi <= 128 && vco_hi <= VCO_MAX) + && (target_vco_freq as i32 - vco_hi as i32).abs() + < (target_vco_freq as i32 - vco_lo as i32).abs() + { (f_hi, vco_hi) } else { (f_lo, vco_lo) @@ -280,18 +271,20 @@ impl CoreClk { // Configure PLL let prci = unsafe { &*PRCI::ptr() }; - prci.pllcfg.modify(|_, w| unsafe { w - .pllr().bits(r) - .pllf().bits(f) - .pllq().bits(q) - .bypass().bit(false) + prci.pllcfg.modify(|_, w| unsafe { + w.pllr() + .bits(r) + .pllf() + .bits(f) + .pllq() + .bits(q) + .bypass() + .bit(false) }); // Configure PLL Output Divider - prci.plloutdiv.write(|w| unsafe { w - .div().bits(divider_div as u8) - .divby1().bit(divider_bypass) - }); + prci.plloutdiv + .write(|w| unsafe { w.div().bits(divider_div as u8).divby1().bit(divider_bypass) }); // Wait for PLL Lock // Note that the Lock signal can be glitchy. @@ -341,12 +334,10 @@ impl AonClk { let div = 4; // LFROSC/5 // Configure LFROSC - aonclk.lfrosccfg.write(|w| { - unsafe { - w.trim().bits(trim); - w.div().bits(div); - w.enable().bit(true) - } + aonclk.lfrosccfg.write(|w| unsafe { + w.trim().bits(trim); + w.div().bits(div); + w.enable().bit(true) }); // Wait for LFROSC to stabilize diff --git a/src/core/clint.rs b/src/core/clint.rs index c3f0e94..0788979 100644 --- a/src/core/clint.rs +++ b/src/core/clint.rs @@ -11,7 +11,7 @@ macro_rules! read64 { return ((hi as u64) << 32) | lo as u64; } } - } + }; } /// Opaque msip register @@ -23,13 +23,9 @@ impl MSIP { /// Set msip register value pub fn set_value(&mut self, value: bool) { unsafe { - (*CLINT::ptr()).msip.write(|w| { - if value { - w.bits(1) - } else { - w.bits(0) - } - }) + (*CLINT::ptr()) + .msip + .write(|w| if value { w.bits(1) } else { w.bits(0) }) } } } @@ -115,7 +111,7 @@ impl From for Clint { Clint { msip: MSIP { _0: () }, mtimecmp: MTIMECMP { _0: () }, - mtime: MTIME + mtime: MTIME, } } } diff --git a/src/core/counters.rs b/src/core/counters.rs index bc98508..84e25b2 100644 --- a/src/core/counters.rs +++ b/src/core/counters.rs @@ -1,6 +1,6 @@ //! Performance counters -use riscv::register::{mcycle, minstret, mhpmcounter3, mhpmcounter4}; +use riscv::register::{mcycle, mhpmcounter3, mhpmcounter4, minstret}; /// Opaque mcycle register pub struct MCYCLE; @@ -56,7 +56,6 @@ pub struct PerformanceCounters { pub mhpmcounter3: MHPMCOUNTER3, /// 40-bit mhpmcounter4 counter pub mhpmcounter4: MHPMCOUNTER4, - // TODO: mhpmevent3, mhpmevent4 } @@ -66,7 +65,7 @@ impl PerformanceCounters { mcycle: MCYCLE, minstret: MINSTRET, mhpmcounter3: MHPMCOUNTER3, - mhpmcounter4: MHPMCOUNTER4 + mhpmcounter4: MHPMCOUNTER4, } } } diff --git a/src/core/mod.rs b/src/core/mod.rs index 9fc06bb..c1bd189 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -21,7 +21,7 @@ impl CorePeripherals { Self { clint: clint.into(), plic: plic.into(), - counters: counters::PerformanceCounters::new() + counters: counters::PerformanceCounters::new(), } } diff --git a/src/core/plic.rs b/src/core/plic.rs index ae1a8bf..c72625f 100644 --- a/src/core/plic.rs +++ b/src/core/plic.rs @@ -1,9 +1,9 @@ //! Platform-Level Interrupt Controller use core::marker::PhantomData; -use riscv::register::{mie, mip}; -use riscv::interrupt::Nr; -use e310x::PLIC; use e310x::Interrupt; +use e310x::PLIC; +use riscv::interrupt::Nr; +use riscv::register::{mie, mip}; /// Priority of a plic::Interrupt. #[derive(Clone, Copy)] @@ -107,12 +107,11 @@ impl From for Plic { mask: 1 << (Interrupt::UART0 as u8), priority_offset: Interrupt::UART0 as usize, _marker: PhantomData, - } + }, } } } - /// Opaque MEXT register. pub struct MEXT { _0: (), @@ -206,8 +205,7 @@ impl INTERRUPT { pub fn enable(&mut self) { // NOTE: should use atomic operations unsafe { - (*PLIC::ptr()).enable[self.offset] - .modify(|r, w| w.bits(r.bits() | self.mask)); + (*PLIC::ptr()).enable[self.offset].modify(|r, w| w.bits(r.bits() | self.mask)); } } @@ -216,35 +214,28 @@ impl INTERRUPT { pub fn disable(&mut self) { // NOTE: should use atomic operations unsafe { - (*PLIC::ptr()).enable[self.offset] - .modify(|r, w| w.bits(r.bits() & !self.mask)); + (*PLIC::ptr()).enable[self.offset].modify(|r, w| w.bits(r.bits() & !self.mask)); } } /// Returns true when IRQ interrupt is pending. pub fn is_pending(&self) -> bool { // NOTE: Atomic write without side effects. - let pending = unsafe { - (*PLIC::ptr()).pending[self.offset].read() - }; + let pending = unsafe { (*PLIC::ptr()).pending[self.offset].read() }; pending.bits() & self.mask == self.mask } /// Returns true when WDOG interrupt is enabled. pub fn is_enabled(&self) -> bool { // NOTE: Atomic write without side effects. - let enabled = unsafe { - (*PLIC::ptr()).enable[self.offset].read() - }; + let enabled = unsafe { (*PLIC::ptr()).enable[self.offset].read() }; enabled.bits() & self.mask == self.mask } /// Returns the priority of the IRQ interrupt. pub fn priority(&self) -> Priority { // NOTE: Atomic read without side effects. - let priority = unsafe { - (*PLIC::ptr()).priority[self.priority_offset].read() - }; + let priority = unsafe { (*PLIC::ptr()).priority[self.priority_offset].read() }; Priority::from(priority.bits()).unwrap() } @@ -252,8 +243,7 @@ impl INTERRUPT { pub fn set_priority(&mut self, priority: Priority) { // NOTE: Atomic write without side effects. unsafe { - (*PLIC::ptr()).priority[self.priority_offset] - .write(|w| w.bits(priority as u32)); + (*PLIC::ptr()).priority[self.priority_offset].write(|w| w.bits(priority as u32)); } } } diff --git a/src/gpio.rs b/src/gpio.rs index 34bf8f8..63239f0 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -56,7 +56,6 @@ pub struct NoInvert; /// Invert output mode (type state) pub struct Invert; - trait PinIndex { const INDEX: usize; } @@ -134,7 +133,6 @@ trait PeripheralAccess { } } - macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, [ $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+ diff --git a/src/i2c.rs b/src/i2c.rs index 3b72be1..d969add 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -10,12 +10,12 @@ //! - SCL: Pin 13 IOF0 //! - Interrupt::I2C0 -use e310x::{I2C0, i2c0}; -use core::ops::Deref; -use core::mem; +use crate::clock::Clocks; use crate::gpio::{gpio0, IOF0}; use crate::time::Bps; -use crate::clock::Clocks; +use core::mem; +use core::ops::Deref; +use e310x::{i2c0, I2C0}; use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; /// SDA pin - DO NOT IMPLEMENT THIS TRAIT @@ -23,8 +23,8 @@ pub unsafe trait SdaPin {} /// SCL pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait SclPin {} -unsafe impl SdaPin for gpio0::Pin12> { } -unsafe impl SclPin for gpio0::Pin13> { } +unsafe impl SdaPin for gpio0::Pin12> {} +unsafe impl SclPin for gpio0::Pin13> {} /// I2C error #[derive(Debug, Eq, PartialEq)] @@ -51,7 +51,6 @@ pub enum Speed { Custom(Bps), } - /// I2C abstraction pub struct I2c { i2c: I2C, @@ -61,7 +60,10 @@ pub struct I2c { impl I2c { /// Configures an I2C peripheral pub fn new(i2c: I2C0, sda: SDA, scl: SCL, speed: Speed, clocks: Clocks) -> Self - where SDA: SdaPin, SCL: SclPin { + where + SDA: SdaPin, + SCL: SclPin, + { // Calculate prescaler value let desired_speed = match speed { Speed::Normal => 100_000, @@ -79,15 +81,17 @@ impl I2c { // Set prescaler let prescaler_lo = (prescaler & 0xff) as u8; let prescaler_hi = ((prescaler >> 8) & 0xff) as u8; - i2c.prer_lo.write(|w| unsafe { w.value().bits(prescaler_lo) }); - i2c.prer_hi.write(|w| unsafe { w.value().bits(prescaler_hi) }); + i2c.prer_lo + .write(|w| unsafe { w.value().bits(prescaler_lo) }); + i2c.prer_hi + .write(|w| unsafe { w.value().bits(prescaler_hi) }); // Turn on i2c i2c.ctr.write(|w| w.en().set_bit()); Self { i2c, - pins: (sda, scl) + pins: (sda, scl), } } } @@ -99,14 +103,15 @@ impl I2c { } } -impl, PINS> I2c { +impl, PINS> I2c { fn reset(&self) { // ACK pending interrupt event, clear commands self.write_cr(|w| w.iack().set_bit()); } fn write_cr(&self, f: F) - where F: FnOnce(&mut i2c0::cr::W) -> &mut i2c0::cr::W + where + F: FnOnce(&mut i2c0::cr::W) -> &mut i2c0::cr::W, { self.i2c.cr().write(|w| unsafe { let mut value: u32 = 0; @@ -116,15 +121,11 @@ impl, PINS> I2c { } fn read_sr(&self) -> i2c0::sr::R { - unsafe { - mem::transmute(self.i2c.sr().read()) - } + unsafe { mem::transmute(self.i2c.sr().read()) } } fn write_byte(&self, byte: u8) { - self.i2c.txr_rxr.write(|w| unsafe { - w.data().bits(byte) - }); + self.i2c.txr_rxr.write(|w| unsafe { w.data().bits(byte) }); } fn read_byte(&self) -> u8 { @@ -171,14 +172,14 @@ impl, PINS> I2c { } fn wait_for_complete(&self) { - while self.read_sr().busy().bit_is_set() { } + while self.read_sr().busy().bit_is_set() {} } } const FLAG_READ: u8 = 1; const FLAG_WRITE: u8 = 0; -impl, PINS> Read for I2c { +impl, PINS> Read for I2c { type Error = Error; fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { @@ -213,7 +214,7 @@ impl, PINS> Read for I2c { } } -impl, PINS> Write for I2c { +impl, PINS> Write for I2c { type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { @@ -245,10 +246,15 @@ impl, PINS> Write for I2c { } } -impl, PINS> WriteRead for I2c { +impl, PINS> WriteRead for I2c { type Error = Error; - fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + fn write_read( + &mut self, + address: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { diff --git a/src/lib.rs b/src/lib.rs index 1326472..2141626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,11 +8,12 @@ pub use e310x; -pub mod core; pub mod clock; +pub mod core; pub mod delay; -pub mod gpio; pub mod device; +pub mod gpio; +pub mod pmu; pub mod prelude; pub mod rtc; pub mod serial; @@ -20,7 +21,6 @@ pub mod spi; pub mod stdout; pub mod time; pub mod wdog; -pub mod pmu; #[cfg(feature = "g002")] pub mod i2c; diff --git a/src/pmu.rs b/src/pmu.rs index 11d134c..075e92d 100644 --- a/src/pmu.rs +++ b/src/pmu.rs @@ -50,7 +50,7 @@ const DEFAULT_WAKE_PROGRAM: [u32; 8] = [ /// /// Enumeration of device reset causes -/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ResetCause { /// Reset due to power on @@ -76,18 +76,18 @@ pub enum WakeupCause { /// /// Errors for user data backup procedures -/// +/// #[derive(Debug)] pub enum BackupError { /// Emitted when user data is larger than backup registers capacity - DataTooLarge, + DataTooLarge, /// Emitted when user data size is not divisible by 4 bytes DataSizeInvalid, } /// /// Wakeup/Reset cause errors -/// +/// #[derive(Debug)] pub enum CauseError { /// Emitted if an unknown wakeup or reset cause is encountered @@ -104,11 +104,11 @@ pub trait PMUExt { /// Puts device to sleep for N seconds, allowing wake-up button to wake it up as well /// /// # Arguments - /// + /// /// *sleep_time* - the amount of time to sleep for in seconds /// /// # Notes - /// + /// /// - enables RTC to be always on /// - sets RTC scale to 1/s /// @@ -116,28 +116,28 @@ pub trait PMUExt { /// /// Returns an enumified version of the Wakeup and Reset causes from the pmucause register - /// + /// /// # Returns - /// + /// /// * `Result` - the cause enum is returned on success - /// + /// /// # Errors - /// + /// /// * `CauseError::InvalidCause` - returned if an unknown wakeup or reset cause is encountered - /// + /// fn wakeup_cause(&self) -> Result; /// /// Stores user data `UD` to backup registers. - /// + /// /// # *WARNING* - /// + /// /// `user_data` value must not contain un-serializable types such as pointers or references. - /// + /// /// `user_data` size must be divisible by 4 bytes. - /// + /// /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** - /// + /// /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` /// /// # Arguments @@ -145,9 +145,9 @@ pub trait PMUExt { /// * `user_data` - reference to the user data to store. `user_data` size must by divisible by 4 bytes /// /// # Returns - /// + /// /// * `Result<(), BackupError>` - `()` is returned on success - /// + /// /// # Errors /// /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers @@ -159,28 +159,28 @@ pub trait PMUExt { /// Restores user data `UD` from backup registers. /// /// # *WARNING* - /// + /// /// `user_data` value must not contain un-serializable types such as pointers or references. - /// + /// /// `user_data` size must be divisible by 4 bytes. - /// + /// /// **The data is only guaranteed to be consistent when program is compiled with the same version of the compiler on store/restore.** - /// + /// /// `#[repr(align(4))]` can be used to enforce a minimum alignment of 4 bytes for `user_data` - /// + /// /// # Arguments /// /// * `user_data` - the user data to restore to. `user_data` size must by divisible by 4 bytes /// /// # Returns - /// + /// /// * `Result<(), BackupError>` - `()` is returned on success - /// + /// /// # Errors /// /// * `BackupError::DataTooLarge` - returned if `user_data` cannot fit into backup registers /// * `BackupError::DataSizeInvalid` - returned if `user_data` size is not divisible by 4 bytes /// - /// + /// unsafe fn restore_backup(&self, user_data: &mut UD) -> Result<(), BackupError>; /// @@ -210,7 +210,9 @@ impl PMUExt for PMU { self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); self.pmuie.write(|w| w.rtc().set_bit().dwakeup().set_bit()); // set RTC clock scale to once per second for easy calculation - (*rtc).rtccfg.write(|w| w.enalways().set_bit().scale().bits(15)); + (*rtc) + .rtccfg + .write(|w| w.enalways().set_bit().scale().bits(15)); // get current RTC clock value scaled let rtc_now = (*rtc).rtcs.read().bits(); // set RTC clock comparator @@ -225,18 +227,18 @@ impl PMUExt for PMU { let pmu_cause = self.pmucause.read(); let wakeup_cause = pmu_cause.wakeupcause(); if wakeup_cause.is_rtc() { - return Ok(WakeupCause::RTC) + return Ok(WakeupCause::RTC); } else if wakeup_cause.is_digital() { - return Ok(WakeupCause::Digital) + return Ok(WakeupCause::Digital); } else if wakeup_cause.is_reset() { let reset_cause = pmu_cause.resetcause(); if reset_cause.is_power_on() { - return Ok(WakeupCause::Reset(ResetCause::PowerOn)) + return Ok(WakeupCause::Reset(ResetCause::PowerOn)); } else if reset_cause.is_external() { - return Ok(WakeupCause::Reset(ResetCause::External)) + return Ok(WakeupCause::Reset(ResetCause::External)); } else if reset_cause.is_watchdog() { - return Ok(WakeupCause::Reset(ResetCause::WatchDog)) + return Ok(WakeupCause::Reset(ResetCause::WatchDog)); } } diff --git a/src/prelude.rs b/src/prelude.rs index db42b0a..c6ccd12 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,16 +1,15 @@ //! Prelude -pub use embedded_hal::prelude::*; -pub use embedded_hal::digital::v2::{ - InputPin as _embedded_hal_digital_v2_InputPin, - OutputPin as _embedded_hal_digital_v2_OutputPin, - StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, - ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, -}; -pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; +pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; +pub use embedded_hal::digital::v2::{ + InputPin as _embedded_hal_digital_v2_InputPin, OutputPin as _embedded_hal_digital_v2_OutputPin, + StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, + ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, +}; +pub use embedded_hal::prelude::*; diff --git a/src/serial.rs b/src/serial.rs index 18d0cda..0184679 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -22,9 +22,9 @@ use nb; use crate::clock::Clocks; use crate::gpio::{gpio0, IOF0}; use crate::time::Bps; +use core::mem; #[allow(unused_imports)] use e310x::{uart0, UART0, UART1}; -use core::mem; // FIXME these should be "closed" traits /// TX pin - DO NOT IMPLEMENT THIS TRAIT @@ -75,7 +75,8 @@ impl Serial { unsafe { uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(false)); uart.div.write(|w| w.bits(div)); - uart.txctrl.write(|w| w.counter().bits(1).enable().bit(true)); + uart.txctrl + .write(|w| w.counter().bits(1).enable().bit(true)); uart.rxctrl.write(|w| w.enable().bit(true)); } @@ -101,11 +102,9 @@ impl Serial { pub fn split(self) -> (Tx, Rx) { ( Tx { - uart: unsafe { mem::zeroed() } + uart: unsafe { mem::zeroed() }, }, - Rx { - uart: self.uart - } + Rx { uart: self.uart }, ) } @@ -160,9 +159,9 @@ impl Serial { /// Configures a UART peripheral to provide serial communication #[deprecated(note = "Please use Serial::new function instead")] pub fn uart0(uart: UART0, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self - where - TX: TxPin, - RX: RxPin, + where + TX: TxPin, + RX: RxPin, { Self::new(uart, pins, baud_rate, clocks) } @@ -173,9 +172,9 @@ impl Serial { /// Configures a UART peripheral to provide serial communication #[deprecated(note = "Please use Serial::new function instead")] pub fn uart1(uart: UART1, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self - where - TX: TxPin, - RX: RxPin, + where + TX: TxPin, + RX: RxPin, { Self::new(uart, pins, baud_rate, clocks) } diff --git a/src/spi.rs b/src/spi.rs index ceb424f..ed139fd 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -23,15 +23,14 @@ //! - SS: Pin 26 IOF0 //! - Interrupt::QSPI2 +use crate::clock::Clocks; +use crate::time::Hertz; use core::convert::Infallible; use core::ops::Deref; +use e310x::{qspi0, QSPI0, QSPI1, QSPI2}; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -use e310x::{QSPI0, QSPI1, QSPI2, qspi0}; -use crate::clock::Clocks; -use crate::time::Hertz; use nb; - /// SPI pins - DO NOT IMPLEMENT THIS TRAIT /// /// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) and (MOSI, MISO, SCK, SS) @@ -48,9 +47,9 @@ impl Pins for () { /* SPI1 pins */ mod spi1_impl { - use crate::gpio::{NoInvert, IOF0}; - use crate::gpio::gpio0; use super::{Pins, QSPI1}; + use crate::gpio::gpio0; + use crate::gpio::{NoInvert, IOF0}; type MOSI = gpio0::Pin3>; type MISO = gpio0::Pin4>; @@ -60,50 +59,90 @@ mod spi1_impl { type SS2 = gpio0::Pin9>; type SS3 = gpio0::Pin10>; - impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } - impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, (), SCK, SS0) { const CS_INDEX: Option = Some(0); } - impl Pins for ((), MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, MISO, SCK, SS1) { const CS_INDEX: Option = Some(1); } - impl Pins for (MOSI, (), SCK, SS1) { const CS_INDEX: Option = Some(1); } - impl Pins for ((), MISO, SCK, SS1) { const CS_INDEX: Option = Some(1); } - impl Pins for (MOSI, MISO, SCK, SS2) { const CS_INDEX: Option = Some(2); } - impl Pins for (MOSI, (), SCK, SS2) { const CS_INDEX: Option = Some(2); } - impl Pins for ((), MISO, SCK, SS2) { const CS_INDEX: Option = Some(2); } - impl Pins for (MOSI, MISO, SCK, SS3) { const CS_INDEX: Option = Some(3); } - impl Pins for (MOSI, (), SCK, SS3) { const CS_INDEX: Option = Some(3); } - impl Pins for ((), MISO, SCK, SS3) { const CS_INDEX: Option = Some(3); } + impl Pins for (MOSI, MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, (), SCK) { + const CS_INDEX: Option = None; + } + impl Pins for ((), MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, MISO, SCK, SS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, (), SCK, SS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for ((), MISO, SCK, SS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, MISO, SCK, SS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for (MOSI, (), SCK, SS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for ((), MISO, SCK, SS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for (MOSI, MISO, SCK, SS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for (MOSI, (), SCK, SS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for ((), MISO, SCK, SS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for (MOSI, MISO, SCK, SS3) { + const CS_INDEX: Option = Some(3); + } + impl Pins for (MOSI, (), SCK, SS3) { + const CS_INDEX: Option = Some(3); + } + impl Pins for ((), MISO, SCK, SS3) { + const CS_INDEX: Option = Some(3); + } } /* SPI2 pins */ mod spi2_impl { - use crate::gpio::{NoInvert, IOF0}; - use crate::gpio::gpio0; use super::{Pins, QSPI2}; + use crate::gpio::gpio0; + use crate::gpio::{NoInvert, IOF0}; type MOSI = gpio0::Pin27>; type MISO = gpio0::Pin28>; type SCK = gpio0::Pin29>; type SS0 = gpio0::Pin26>; - impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } - impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, (), SCK, SS0) { const CS_INDEX: Option = Some(0); } - impl Pins for ((), MISO, SCK, SS0) { const CS_INDEX: Option = Some(0); } + impl Pins for (MOSI, MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, (), SCK) { + const CS_INDEX: Option = None; + } + impl Pins for ((), MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, MISO, SCK, SS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, (), SCK, SS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for ((), MISO, SCK, SS0) { + const CS_INDEX: Option = Some(0); + } } - #[doc(hidden)] pub trait SpiX: Deref {} impl SpiX for QSPI0 {} impl SpiX for QSPI1 {} impl SpiX for QSPI2 {} - /// SPI abstraction pub struct Spi { spi: SPI, @@ -115,7 +154,7 @@ impl Spi { /// Defaults to using AUTO CS in FRAME mode if PINS configuration allows it pub fn new(spi: SPI, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self where - PINS: Pins + PINS: Pins, { let div = clocks.tlclk().0 / (2 * freq.0) - 1; assert!(div <= 0xfff); @@ -136,16 +175,18 @@ impl Spi { // Set SPI mode let phase = mode.phase == Phase::CaptureOnSecondTransition; let polarity = mode.polarity == Polarity::IdleHigh; - spi.sckmode.write(|w| w - .pha().bit(phase) - .pol().bit(polarity) - ); - - spi.fmt.write(|w| unsafe { w - .proto().bits(0) // Single - .endian().clear_bit() // Transmit most-significant bit (MSB) first - .dir().rx() - .len().bits(8) + spi.sckmode + .write(|w| w.pha().bit(phase).pol().bit(polarity)); + + spi.fmt.write(|w| unsafe { + w.proto() + .bits(0) // Single + .endian() + .clear_bit() // Transmit most-significant bit (MSB) first + .dir() + .rx() + .len() + .bits(8) }); // Set watermark levels @@ -251,9 +292,9 @@ impl embedded_hal::spi::FullDuplex for Spi { impl embedded_hal::blocking::spi::Transfer for Spi { type Error = Infallible; - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w[u8], Self::Error> { + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() { } + while self.spi.rxdata.read().empty().bit_is_clear() {} self.cs_mode_frame(); @@ -286,7 +327,7 @@ impl embedded_hal::blocking::spi::Write for Spi fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() { } + while self.spi.rxdata.read().empty().bit_is_clear() {} self.cs_mode_frame(); @@ -318,12 +359,12 @@ impl embedded_hal::blocking::spi::WriteIter for Spi(&mut self, words: WI) -> Result<(), Self::Error> where - WI: IntoIterator + WI: IntoIterator, { let mut iter = words.into_iter(); // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() { } + while self.spi.rxdata.read().empty().bit_is_clear() {} self.cs_mode_frame(); @@ -353,14 +394,13 @@ impl embedded_hal::blocking::spi::WriteIter for Spi Spi { /// Configures the SPI peripheral to operate in full duplex master mode #[deprecated(note = "Please use Spi::new function instead")] pub fn spi0(spi: QSPI0, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self where - PINS: Pins + PINS: Pins, { Self::new(spi, pins, mode, freq, clocks) } @@ -370,8 +410,8 @@ impl Spi { /// Configures the SPI peripheral to operate in full duplex master mode #[deprecated(note = "Please use Spi::new function instead")] pub fn spi1(spi: QSPI1, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins + where + PINS: Pins, { Self::new(spi, pins, mode, freq, clocks) } @@ -381,8 +421,8 @@ impl Spi { /// Configures the SPI peripheral to operate in full duplex master mode #[deprecated(note = "Please use Spi::new function instead")] pub fn spi2(spi: QSPI2, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins + where + PINS: Pins, { Self::new(spi, pins, mode, freq, clocks) } diff --git a/src/stdout.rs b/src/stdout.rs index 57785fb..004bcc8 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -5,11 +5,11 @@ use nb::block; /// Stdout implements the core::fmt::Write trait for hal::serial::Write /// implementations. pub struct Stdout<'p, T>(pub &'p mut T) - where +where T: 'p; impl<'p, T> Write for Stdout<'p, T> - where +where T: embedded_hal::serial::Write, { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { diff --git a/src/wdog.rs b/src/wdog.rs index 2adf74a..2abba57 100644 --- a/src/wdog.rs +++ b/src/wdog.rs @@ -57,12 +57,18 @@ impl WdogCfg { pub fn freeze(self) -> Wdog { unsafe { (*WDOG::ptr()).wdogkey.write(|w| w.bits(0x51F15E)); - (*WDOG::ptr()).wdogcfg.write(|w| w - .scale().bits(self.scale) - .rsten().bit(self.reset) - .zerocmp().bit(self.zero_cmp) - .enalways().bit(self.enable) - .encoreawake().bit(self.awake)); + (*WDOG::ptr()).wdogcfg.write(|w| { + w.scale() + .bits(self.scale) + .rsten() + .bit(self.reset) + .zerocmp() + .bit(self.zero_cmp) + .enalways() + .bit(self.enable) + .encoreawake() + .bit(self.awake) + }); } Wdog { _0: () } } From fce75e068c4604ef893057e27fcc031539c0fdd1 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 17 Jul 2021 13:39:33 -0700 Subject: [PATCH 247/315] release v0.9.2 --- CHANGELOG.md | 6 ++++++ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eba48f8..d2b4a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.9.2] - 2021-07-17 + +### Changed + +- Fixed `e310x-hal::delay::Delay` timing typo with extra 0 + ## [v0.9.1] - 2021-07-15 ### Added diff --git a/Cargo.toml b/Cargo.toml index 36e72d3..b79f6d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.1" +version = "0.9.2" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From 924abb27461e38e19c03c0c537936fc8d6c4dbf6 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 19 Jul 2021 12:42:50 -0700 Subject: [PATCH 248/315] use GHA --- .github/bors.toml | 8 ++++- .github/workflows/ci.yaml | 57 ++++++++++++++++++++++++++++++++++ .github/workflows/rustfmt.yaml | 24 ++++++++++++++ README.md | 5 +++ ci/install.sh | 5 --- ci/script.sh | 6 ---- 6 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/rustfmt.yaml delete mode 100755 ci/install.sh delete mode 100755 ci/script.sh diff --git a/.github/bors.toml b/.github/bors.toml index ca42be0..b5b4935 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -1,4 +1,10 @@ block_labels = ["needs-decision"] delete_merged_branches = true required_approvals = 1 -status = ["continuous-integration/travis-ci/push"] +status = [ + "ci-linux (stable)", + "ci-linux (1.42.0)", + "build-other (macOS-latest)", + "build-other (windows-latest)", + "Rustfmt" +] diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..0193070 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,57 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Continuous integration + +jobs: + ci-linux: + runs-on: ubuntu-20.04 + continue-on-error: ${{ matrix.experimental || false }} + strategy: + matrix: + # All generated code should be running on stable now, MRSV is 1.42.0 + rust: [nightly, stable, 1.42.0] + + include: + # Nightly is only for reference and allowed to fail + - rust: nightly + experimental: true + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Install all Rust targets for ${{ matrix.rust }} + run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf + - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} + run: TARGET=x86_64-unknown-linux-gnu cargo check && TARGET=x86_64-unknown-linux-gnu cargo check --features g002 + - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} + run: TARGET=riscv32imac-unknown-none-elf cargo check && TARGET=riscv32imac-unknown-none-elf cargo check --features g002 + - name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} + run: TARGET=riscv64imac-unknown-none-elf cargo check && TARGET=riscv64imac-unknown-none-elf cargo check --features g002 + - name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} + run: TARGET=riscv64gc-unknown-none-elf cargo check && TARGET=riscv64gc-unknown-none-elf cargo check --features g002 + + # On macOS and Windows, we at least make sure that the crate builds and links. + build-other: + strategy: + matrix: + os: + - macOS-latest + - windows-latest + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: Build crate for host OS + run: cargo build && cargo build --features g002 \ No newline at end of file diff --git a/.github/workflows/rustfmt.yaml b/.github/workflows/rustfmt.yaml new file mode 100644 index 0000000..0727384 --- /dev/null +++ b/.github/workflows/rustfmt.yaml @@ -0,0 +1,24 @@ + +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Code formatting check + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check \ No newline at end of file diff --git a/README.md b/README.md index cb05b3c..81455da 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,11 @@ This project is developed and maintained by the [RISC-V team][team]. ## [Documentation](https://docs.rs/crate/e310x-hal) +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +compile with older versions but that may change in any new patch release. + ## License Copyright 2018-2019 [RISC-V team][team] diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index ce4ea1e..0000000 --- a/ci/install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -rustup target add $TARGET diff --git a/ci/script.sh b/ci/script.sh deleted file mode 100755 index c048a90..0000000 --- a/ci/script.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -cargo check --target $TARGET -cargo check --target $TARGET --features g002 From 844d648b6d48ecfcbe22fb3c433b57a10562a974 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 20 Jul 2021 09:08:23 -0700 Subject: [PATCH 249/315] use --target for CI checks --- .github/workflows/ci.yaml | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0193070..f185484 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,13 +29,21 @@ jobs: - name: Install all Rust targets for ${{ matrix.rust }} run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} - run: TARGET=x86_64-unknown-linux-gnu cargo check && TARGET=x86_64-unknown-linux-gnu cargo check --features g002 + run: | + cargo check --target x86_64-unknown-linux-gnu + cargo check --target x86_64-unknown-linux-gnu --features g002 - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} - run: TARGET=riscv32imac-unknown-none-elf cargo check && TARGET=riscv32imac-unknown-none-elf cargo check --features g002 + run: | + cargo check --target riscv32imac-unknown-none-elf + cargo check --target riscv32imac-unknown-none-elf --features g002 - name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} - run: TARGET=riscv64imac-unknown-none-elf cargo check && TARGET=riscv64imac-unknown-none-elf cargo check --features g002 + run: | + cargo check --target riscv64imac-unknown-none-elf + cargo check --target riscv64imac-unknown-none-elf --features g002 - name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} - run: TARGET=riscv64gc-unknown-none-elf cargo check && TARGET=riscv64gc-unknown-none-elf cargo check --features g002 + run: | + cargo check --target riscv64gc-unknown-none-elf + cargo check --target riscv64gc-unknown-none-elf --features g002 # On macOS and Windows, we at least make sure that the crate builds and links. build-other: @@ -54,4 +62,6 @@ jobs: toolchain: stable override: true - name: Build crate for host OS - run: cargo build && cargo build --features g002 \ No newline at end of file + run: | + cargo build + cargo build --features g002 \ No newline at end of file From 19d97710d7a39aa6614ecc96647ea53bee6210e0 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 20 Jul 2021 09:17:16 -0700 Subject: [PATCH 250/315] use GHA --- .github/bors.toml | 8 +++- .github/workflows/ci.yaml | 82 ++++++++++++++++++++++++++++++++++ .github/workflows/rustfmt.yaml | 24 ++++++++++ README.md | 5 +++ ci/install.sh | 5 --- ci/script.sh | 9 ---- 6 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/rustfmt.yaml delete mode 100755 ci/install.sh delete mode 100755 ci/script.sh diff --git a/.github/bors.toml b/.github/bors.toml index ca42be0..b5b4935 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -1,4 +1,10 @@ block_labels = ["needs-decision"] delete_merged_branches = true required_approvals = 1 -status = ["continuous-integration/travis-ci/push"] +status = [ + "ci-linux (stable)", + "ci-linux (1.42.0)", + "build-other (macOS-latest)", + "build-other (windows-latest)", + "Rustfmt" +] diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..bdb839f --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,82 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Continuous integration + +jobs: + ci-linux: + runs-on: ubuntu-20.04 + continue-on-error: ${{ matrix.experimental || false }} + strategy: + matrix: + # All generated code should be running on stable now, MRSV is 1.42.0 + rust: [nightly, stable, 1.42.0] + + include: + # Nightly is only for reference and allowed to fail + - rust: nightly + experimental: true + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + - name: Install all Rust targets for ${{ matrix.rust }} + run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf + - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} + run: | + cargo check --target x86_64-unknown-linux-gnu --features board-hifive1 + cargo check --target x86_64-unknown-linux-gnu --features board-hifive1-revb + cargo check --target x86_64-unknown-linux-gnu --features board-redv + cargo check --target x86_64-unknown-linux-gnu --features board-lofive + cargo check --target x86_64-unknown-linux-gnu --features board-lofive-r1 + - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} + run: | + cargo check --target riscv32imac-unknown-none-elf --features board-hifive1 + cargo check --target riscv32imac-unknown-none-elf --features board-hifive1-revb + cargo check --target riscv32imac-unknown-none-elf --features board-redv + cargo check --target riscv32imac-unknown-none-elf --features board-lofive + cargo check --target riscv32imac-unknown-none-elf --features board-lofive-r1 + - name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} + run: | + cargo check --target riscv64imac-unknown-none-elf --features board-hifive1 + cargo check --target riscv64imac-unknown-none-elf --features board-hifive1-revb + cargo check --target riscv64imac-unknown-none-elf --features board-redv + cargo check --target riscv64imac-unknown-none-elf --features board-lofive + cargo check --target riscv64imac-unknown-none-elf --features board-lofive-r1 + - name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} + run: | + cargo check --target riscv64gc-unknown-none-elf --features board-hifive1 + cargo check --target riscv64gc-unknown-none-elf --features board-hifive1-revb + cargo check --target riscv64gc-unknown-none-elf --features board-redv + cargo check --target riscv64gc-unknown-none-elf --features board-lofive + cargo check --target riscv64gc-unknown-none-elf --features board-lofive-r1 + + # On macOS and Windows, we at least make sure that the crate builds and links. + build-other: + strategy: + matrix: + os: + - macOS-latest + - windows-latest + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: Build crate for host OS + run: | + cargo build --features board-hifive1 + cargo build --features board-hifive1-revb + cargo build --features board-redv + cargo build --features board-lofive + cargo build --features board-lofive-r1 \ No newline at end of file diff --git a/.github/workflows/rustfmt.yaml b/.github/workflows/rustfmt.yaml new file mode 100644 index 0000000..0727384 --- /dev/null +++ b/.github/workflows/rustfmt.yaml @@ -0,0 +1,24 @@ + +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Code formatting check + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check \ No newline at end of file diff --git a/README.md b/README.md index a16a2e4..593b26c 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ ## [Documentation](https://docs.rs/crate/hifive1) +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +compile with older versions but that may change in any new patch release. + ## License Copyright 2018-2019 [RISC-V team][team] diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index b2789a8..0000000 --- a/ci/install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -euxo pipefail - -rustup target add $TARGET diff --git a/ci/script.sh b/ci/script.sh deleted file mode 100755 index c5bc32b..0000000 --- a/ci/script.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -euxo pipefail - -cargo check --target $TARGET --features 'board-hifive1' -cargo check --target $TARGET --features 'board-hifive1-revb' -cargo check --target $TARGET --features 'board-redv' -cargo check --target $TARGET --features 'board-lofive' -cargo check --target $TARGET --features 'board-lofive-r1' From 288ef2878dfd57c674757c8003459befa9a33ef6 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 20 Jul 2021 23:03:07 -0700 Subject: [PATCH 251/315] remove unused target checks --- .github/workflows/ci.yaml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bdb839f..3d9685b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,13 +28,6 @@ jobs: override: true - name: Install all Rust targets for ${{ matrix.rust }} run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} - run: | - cargo check --target x86_64-unknown-linux-gnu --features board-hifive1 - cargo check --target x86_64-unknown-linux-gnu --features board-hifive1-revb - cargo check --target x86_64-unknown-linux-gnu --features board-redv - cargo check --target x86_64-unknown-linux-gnu --features board-lofive - cargo check --target x86_64-unknown-linux-gnu --features board-lofive-r1 - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} run: | cargo check --target riscv32imac-unknown-none-elf --features board-hifive1 @@ -42,20 +35,6 @@ jobs: cargo check --target riscv32imac-unknown-none-elf --features board-redv cargo check --target riscv32imac-unknown-none-elf --features board-lofive cargo check --target riscv32imac-unknown-none-elf --features board-lofive-r1 - - name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv64imac-unknown-none-elf --features board-hifive1 - cargo check --target riscv64imac-unknown-none-elf --features board-hifive1-revb - cargo check --target riscv64imac-unknown-none-elf --features board-redv - cargo check --target riscv64imac-unknown-none-elf --features board-lofive - cargo check --target riscv64imac-unknown-none-elf --features board-lofive-r1 - - name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv64gc-unknown-none-elf --features board-hifive1 - cargo check --target riscv64gc-unknown-none-elf --features board-hifive1-revb - cargo check --target riscv64gc-unknown-none-elf --features board-redv - cargo check --target riscv64gc-unknown-none-elf --features board-lofive - cargo check --target riscv64gc-unknown-none-elf --features board-lofive-r1 # On macOS and Windows, we at least make sure that the crate builds and links. build-other: From 3d2903fdfaab05e34b35930c544f7735c0c51948 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 20 Jul 2021 23:04:03 -0700 Subject: [PATCH 252/315] remove unused target checks --- .github/workflows/ci.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f185484..2addd1a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,22 +28,10 @@ jobs: override: true - name: Install all Rust targets for ${{ matrix.rust }} run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - - name: Run CI script for x86_64-unknown-linux-gnu under ${{ matrix.rust }} - run: | - cargo check --target x86_64-unknown-linux-gnu - cargo check --target x86_64-unknown-linux-gnu --features g002 - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} run: | cargo check --target riscv32imac-unknown-none-elf cargo check --target riscv32imac-unknown-none-elf --features g002 - - name: Run CI script for riscv64imac-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv64imac-unknown-none-elf - cargo check --target riscv64imac-unknown-none-elf --features g002 - - name: Run CI script for riscv64gc-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv64gc-unknown-none-elf - cargo check --target riscv64gc-unknown-none-elf --features g002 # On macOS and Windows, we at least make sure that the crate builds and links. build-other: From 9c42bb9b3e1de5d1d858d69eff30303a275b9b59 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Aug 2021 14:24:14 +0300 Subject: [PATCH 253/315] Improve DelayMs/DelayUs implementations --- src/delay.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/delay.rs b/src/delay.rs index 297620d..47921b4 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -27,13 +27,24 @@ impl DelayUs for Delay { } } +// This is a workaround to allow `delay_us(42)` construction without specifying a type. +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: i32) { + assert!(us >= 0); + self.delay_us(us as u32); + } +} + impl DelayUs for Delay { + #[inline(always)] fn delay_us(&mut self, us: u16) { self.delay_ms(u32::from(us)); } } impl DelayUs for Delay { + #[inline(always)] fn delay_us(&mut self, us: u8) { self.delay_ms(u32::from(us)); } @@ -45,13 +56,24 @@ impl DelayMs for Delay { } } +// This is a workaround to allow `delay_ms(42)` construction without specifying a type. +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: i32) { + assert!(ms >= 0); + self.delay_ms(ms as u32); + } +} + impl DelayMs for Delay { + #[inline(always)] fn delay_ms(&mut self, ms: u16) { self.delay_ms(u32::from(ms)); } } impl DelayMs for Delay { + #[inline(always)] fn delay_ms(&mut self, ms: u8) { self.delay_ms(u32::from(ms)); } @@ -107,13 +129,24 @@ impl DelayMs for Sleep { } } +// This is a workaround to allow `delay_ms(42)` construction without specifying a type. +impl DelayMs for Sleep { + #[inline(always)] + fn delay_ms(&mut self, ms: i32) { + assert!(ms >= 0); + self.delay_ms(ms as u32); + } +} + impl DelayMs for Sleep { + #[inline(always)] fn delay_ms(&mut self, ms: u16) { self.delay_ms(u32::from(ms)); } } impl DelayMs for Sleep { + #[inline(always)] fn delay_ms(&mut self, ms: u8) { self.delay_ms(u32::from(ms)); } From ddb7942beb808b77d0c08fe80769e7d55a987654 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Aug 2021 14:38:25 +0300 Subject: [PATCH 254/315] Use enum variants in the SPI driver --- src/spi.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/spi.rs b/src/spi.rs index ed139fd..6daa929 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -27,6 +27,7 @@ use crate::clock::Clocks; use crate::time::Hertz; use core::convert::Infallible; use core::ops::Deref; +use e310x::qspi0::csmode::MODE_A; use e310x::{qspi0, QSPI0, QSPI1, QSPI2}; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use nb; @@ -163,11 +164,11 @@ impl Spi { let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { spi.csid.write(|w| unsafe { w.bits(cs_index) }); - 2 // AUTO: Assert/de-assert CS at the beginning/end of each frame + MODE_A::HOLD // Keep CS continuously asserted after the initial frame } else { - 3 // OFF: Disable hardware control of the CS pin + MODE_A::OFF // Disable hardware control of the CS pin }; - spi.csmode.write(|w| unsafe { w.bits(cs_mode) }); + spi.csmode.write(|w| w.mode().variant(cs_mode)); // Set CS pin polarity to high spi.csdef.reset(); @@ -179,14 +180,10 @@ impl Spi { .write(|w| w.pha().bit(phase).pol().bit(polarity)); spi.fmt.write(|w| unsafe { - w.proto() - .bits(0) // Single - .endian() - .clear_bit() // Transmit most-significant bit (MSB) first - .dir() - .rx() - .len() - .bits(8) + w.proto().single(); + w.endian().big(); // Transmit most-significant bit (MSB) first + w.dir().rx(); + w.len().bits(8) }); // Set watermark levels @@ -241,15 +238,15 @@ impl Spi { /// Set AUTO CS mode to per-word operation pub fn cs_mode_word(&mut self) { - if self.spi.csmode.read().bits() != 3 { - self.spi.csmode.write(|w| unsafe { w.bits(0) }); + if !self.spi.csmode.read().mode().is_off() { + self.spi.csmode.write(|w| w.mode().auto()); } } /// Set AUTO CS mode to per-frame operation pub fn cs_mode_frame(&mut self) { - if self.spi.csmode.read().bits() != 3 { - self.spi.csmode.write(|w| unsafe { w.bits(2) }); + if !self.spi.csmode.read().mode().is_off() { + self.spi.csmode.write(|w| w.mode().hold()); } } From a100c100655eabe58155c953a7321ac30e7e3f02 Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 1 Aug 2021 18:46:23 +0300 Subject: [PATCH 255/315] Fix comment --- src/spi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi.rs b/src/spi.rs index 6daa929..39ff562 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -243,7 +243,7 @@ impl Spi { } } - /// Set AUTO CS mode to per-frame operation + /// Set HOLD CS mode to per-frame operation pub fn cs_mode_frame(&mut self) { if !self.spi.csmode.read().mode().is_off() { self.spi.csmode.write(|w| w.mode().hold()); From bae578369602785a332e602e943ba44ca7fd3d7c Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 12 Aug 2021 13:27:35 -0700 Subject: [PATCH 256/315] fix DelayUs using millisecond variants by typo --- src/delay.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index 47921b4..4778bf1 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -19,7 +19,7 @@ impl Delay { impl DelayUs for Delay { fn delay_us(&mut self, us: u32) { - let ticks = (us as u64) * TICKS_PER_SECOND / 1000_000; + let ticks = (us as u64) * TICKS_PER_SECOND / 1_000_000; let mtime = MTIME; let t = mtime.mtime() + ticks; @@ -39,14 +39,14 @@ impl DelayUs for Delay { impl DelayUs for Delay { #[inline(always)] fn delay_us(&mut self, us: u16) { - self.delay_ms(u32::from(us)); + self.delay_us(u32::from(us)); } } impl DelayUs for Delay { #[inline(always)] fn delay_us(&mut self, us: u8) { - self.delay_ms(u32::from(us)); + self.delay_us(u32::from(us)); } } From a3c58d6127be10b51054b8e5f3517664941d1c67 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 12 Aug 2021 13:29:51 -0700 Subject: [PATCH 257/315] add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2b4a20..e192270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Fixed `e310x-hal::delay::Delay` call typo to `delay_ms` + ## [v0.9.2] - 2021-07-17 ### Changed From 0d8721241385fa531785c342fbf853e060d54ba6 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 15 Aug 2021 13:29:02 -0700 Subject: [PATCH 258/315] release v0.9.3 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e192270..f782c0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.9.3] - 2021-08-15 + +### Changed + - Fixed `e310x-hal::delay::Delay` call typo to `delay_ms` ## [v0.9.2] - 2021-07-17 diff --git a/Cargo.toml b/Cargo.toml index b79f6d0..41e5b24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.2" +version = "0.9.3" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From c63028db1b0eda424af862779d0fc1528503c46d Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 16 Aug 2021 09:42:18 -0700 Subject: [PATCH 259/315] update riscv dependency to 0.7 --- Cargo.toml | 2 +- src/core/plic.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 41e5b24..1d64127 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "1.0.0" -riscv = "0.6.0" +riscv = "0.7.0" e310x = { version = "0.9.0", features = ["rt"] } [features] diff --git a/src/core/plic.rs b/src/core/plic.rs index c72625f..2130afa 100644 --- a/src/core/plic.rs +++ b/src/core/plic.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; use e310x::Interrupt; use e310x::PLIC; -use riscv::interrupt::Nr; use riscv::register::{mie, mip}; /// Priority of a plic::Interrupt. @@ -183,7 +182,7 @@ impl CLAIM { pub fn complete(&mut self, intr: Interrupt) { // NOTE: Atomic write with side effects. unsafe { - (*PLIC::ptr()).claim.write(|w| w.bits(intr.nr() as u32)); + (*PLIC::ptr()).claim.write(|w| w.bits(intr as u32)); } } } From 4d63a87b75802b15708a8faae0cba7027e0490e8 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 29 Jul 2021 23:02:06 -0700 Subject: [PATCH 260/315] refactor spi into bus and devices for sharing --- CHANGELOG.md | 2 + Cargo.toml | 2 +- src/spi.rs | 452 ++++-------------------------------- src/spi/bus.rs | 250 ++++++++++++++++++++ src/spi/config.rs | 69 ++++++ src/spi/exclusive_device.rs | 120 ++++++++++ src/spi/shared_bus.rs | 70 ++++++ src/spi/shared_device.rs | 165 +++++++++++++ src/spi/traits.rs | 206 ++++++++++++++++ 9 files changed, 928 insertions(+), 408 deletions(-) create mode 100644 src/spi/bus.rs create mode 100644 src/spi/config.rs create mode 100644 src/spi/exclusive_device.rs create mode 100644 src/spi/shared_bus.rs create mode 100644 src/spi/shared_device.rs create mode 100644 src/spi/traits.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f782c0f..9966133 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist + ## [v0.9.3] - 2021-08-15 ### Changed diff --git a/Cargo.toml b/Cargo.toml index 1d64127..e79aed9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = { version = "0.2.3", features = ["unproven"] } +embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" e310x = { version = "0.9.0", features = ["rt"] } diff --git a/src/spi.rs b/src/spi.rs index 39ff562..d508849 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -9,10 +9,10 @@ //! - MOSI: Pin 3 IOF0 //! - MISO: Pin 4 IOF0 //! - SCK: Pin 5 IOF0 -//! - SS0: Pin 2 IOF0 -//! - SS1: Pin 8 IOF0 (not connected to package in FE310) -//! - SS2: Pin 9 IOF0 -//! - SS3: Pin 10 IOF0 +//! - CS0: Pin 2 IOF0 +//! - CS1: Pin 8 IOF0 (not connected to package in FE310) +//! - CS2: Pin 9 IOF0 +//! - CS3: Pin 10 IOF0 //! - Interrupt::QSPI1 //! //! # QSPI2 @@ -20,407 +20,45 @@ //! - MOSI: Pin 27 IOF0 //! - MISO: Pin 28 IOF0 //! - SCK: Pin 29 IOF0 -//! - SS: Pin 26 IOF0 +//! - CS: Pin 26 IOF0 //! - Interrupt::QSPI2 - -use crate::clock::Clocks; -use crate::time::Hertz; -use core::convert::Infallible; -use core::ops::Deref; -use e310x::qspi0::csmode::MODE_A; -use e310x::{qspi0, QSPI0, QSPI1, QSPI2}; -pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -use nb; - -/// SPI pins - DO NOT IMPLEMENT THIS TRAIT -/// -/// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) and (MOSI, MISO, SCK, SS) -/// and combinations without MOSI/MISO -pub trait Pins { - #[doc(hidden)] - const CS_INDEX: Option; -} - -/* SPI0 pins */ -impl Pins for () { - const CS_INDEX: Option = Some(0); -} - -/* SPI1 pins */ -mod spi1_impl { - use super::{Pins, QSPI1}; - use crate::gpio::gpio0; - use crate::gpio::{NoInvert, IOF0}; - - type MOSI = gpio0::Pin3>; - type MISO = gpio0::Pin4>; - type SCK = gpio0::Pin5>; - type SS0 = gpio0::Pin2>; - type SS1 = gpio0::Pin8>; - type SS2 = gpio0::Pin9>; - type SS3 = gpio0::Pin10>; - - impl Pins for (MOSI, MISO, SCK) { - const CS_INDEX: Option = None; - } - impl Pins for (MOSI, (), SCK) { - const CS_INDEX: Option = None; - } - impl Pins for ((), MISO, SCK) { - const CS_INDEX: Option = None; - } - impl Pins for (MOSI, MISO, SCK, SS0) { - const CS_INDEX: Option = Some(0); - } - impl Pins for (MOSI, (), SCK, SS0) { - const CS_INDEX: Option = Some(0); - } - impl Pins for ((), MISO, SCK, SS0) { - const CS_INDEX: Option = Some(0); - } - impl Pins for (MOSI, MISO, SCK, SS1) { - const CS_INDEX: Option = Some(1); - } - impl Pins for (MOSI, (), SCK, SS1) { - const CS_INDEX: Option = Some(1); - } - impl Pins for ((), MISO, SCK, SS1) { - const CS_INDEX: Option = Some(1); - } - impl Pins for (MOSI, MISO, SCK, SS2) { - const CS_INDEX: Option = Some(2); - } - impl Pins for (MOSI, (), SCK, SS2) { - const CS_INDEX: Option = Some(2); - } - impl Pins for ((), MISO, SCK, SS2) { - const CS_INDEX: Option = Some(2); - } - impl Pins for (MOSI, MISO, SCK, SS3) { - const CS_INDEX: Option = Some(3); - } - impl Pins for (MOSI, (), SCK, SS3) { - const CS_INDEX: Option = Some(3); - } - impl Pins for ((), MISO, SCK, SS3) { - const CS_INDEX: Option = Some(3); - } -} - -/* SPI2 pins */ -mod spi2_impl { - use super::{Pins, QSPI2}; - use crate::gpio::gpio0; - use crate::gpio::{NoInvert, IOF0}; - - type MOSI = gpio0::Pin27>; - type MISO = gpio0::Pin28>; - type SCK = gpio0::Pin29>; - type SS0 = gpio0::Pin26>; - - impl Pins for (MOSI, MISO, SCK) { - const CS_INDEX: Option = None; - } - impl Pins for (MOSI, (), SCK) { - const CS_INDEX: Option = None; - } - impl Pins for ((), MISO, SCK) { - const CS_INDEX: Option = None; - } - impl Pins for (MOSI, MISO, SCK, SS0) { - const CS_INDEX: Option = Some(0); - } - impl Pins for (MOSI, (), SCK, SS0) { - const CS_INDEX: Option = Some(0); - } - impl Pins for ((), MISO, SCK, SS0) { - const CS_INDEX: Option = Some(0); - } -} - -#[doc(hidden)] -pub trait SpiX: Deref {} -impl SpiX for QSPI0 {} -impl SpiX for QSPI1 {} -impl SpiX for QSPI2 {} - -/// SPI abstraction -pub struct Spi { - spi: SPI, - pins: PINS, -} - -impl Spi { - /// Configures the SPI peripheral to operate in full duplex master mode - /// Defaults to using AUTO CS in FRAME mode if PINS configuration allows it - pub fn new(spi: SPI, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins, - { - let div = clocks.tlclk().0 / (2 * freq.0) - 1; - assert!(div <= 0xfff); - spi.sckdiv.write(|w| unsafe { w.div().bits(div as u16) }); - - let cs_mode = if let Some(cs_index) = PINS::CS_INDEX { - spi.csid.write(|w| unsafe { w.bits(cs_index) }); - - MODE_A::HOLD // Keep CS continuously asserted after the initial frame - } else { - MODE_A::OFF // Disable hardware control of the CS pin - }; - spi.csmode.write(|w| w.mode().variant(cs_mode)); - - // Set CS pin polarity to high - spi.csdef.reset(); - - // Set SPI mode - let phase = mode.phase == Phase::CaptureOnSecondTransition; - let polarity = mode.polarity == Polarity::IdleHigh; - spi.sckmode - .write(|w| w.pha().bit(phase).pol().bit(polarity)); - - spi.fmt.write(|w| unsafe { - w.proto().single(); - w.endian().big(); // Transmit most-significant bit (MSB) first - w.dir().rx(); - w.len().bits(8) - }); - - // Set watermark levels - spi.txmark.write(|w| unsafe { w.txmark().bits(1) }); - spi.rxmark.write(|w| unsafe { w.rxmark().bits(0) }); - - spi.delay0.reset(); - spi.delay1.reset(); - - Self { spi, pins } - } - - /// Sets transmit watermark level - pub fn set_tx_watermark(&mut self, value: u8) { - self.spi.txmark.write(|w| unsafe { w.txmark().bits(value) }); - } - - /// Sets receive watermark level - pub fn set_rx_watermark(&mut self, value: u8) { - self.spi.rxmark.write(|w| unsafe { w.rxmark().bits(value) }); - } - - /// Returns transmit watermark event status - pub fn tx_wm_is_pending(&self) -> bool { - self.spi.ip.read().txwm().bit() - } - - /// Returns receive watermark event status - pub fn rx_wm_is_pending(&self) -> bool { - self.spi.ip.read().rxwm().bit() - } - - /// Starts listening for transmit watermark interrupt event - pub fn listen_tx_wm(&mut self) { - self.spi.ie.write(|w| w.txwm().set_bit()) - } - - /// Starts listening for receive watermark interrupt event - pub fn listen_rx_wm(&mut self) { - self.spi.ie.write(|w| w.rxwm().set_bit()) - } - - /// Stops listening for transmit watermark interrupt event - pub fn unlisten_tx_wm(&mut self) { - self.spi.ie.write(|w| w.txwm().clear_bit()) - } - - /// Stops listening for receive watermark interrupt event - pub fn unlisten_rx_wm(&mut self) { - self.spi.ie.write(|w| w.rxwm().clear_bit()) - } - - /// Set AUTO CS mode to per-word operation - pub fn cs_mode_word(&mut self) { - if !self.spi.csmode.read().mode().is_off() { - self.spi.csmode.write(|w| w.mode().auto()); - } - } - - /// Set HOLD CS mode to per-frame operation - pub fn cs_mode_frame(&mut self) { - if !self.spi.csmode.read().mode().is_off() { - self.spi.csmode.write(|w| w.mode().hold()); - } - } - - /// Finishes transfer by deasserting CS (only for hardware-controlled CS) - pub fn end_transfer(&mut self) { - self.cs_mode_word() - } - - /// Releases the SPI peripheral and associated pins - pub fn free(self) -> (SPI, PINS) { - (self.spi, self.pins) - } -} - -impl embedded_hal::spi::FullDuplex for Spi { - type Error = Infallible; - - fn read(&mut self) -> nb::Result { - let rxdata = self.spi.rxdata.read(); - - if rxdata.empty().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - Ok(rxdata.data().bits()) - } - } - - fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - let txdata = self.spi.txdata.read(); - - if txdata.full().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); - Ok(()) - } - } -} - -impl embedded_hal::blocking::spi::Transfer for Spi { - type Error = Infallible; - - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() {} - - self.cs_mode_frame(); - - let mut iwrite = 0; - let mut iread = 0; - while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { - let byte = unsafe { words.get_unchecked(iwrite) }; - iwrite += 1; - self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); - } - - if iread < iwrite { - let data = self.spi.rxdata.read(); - if data.empty().bit_is_clear() { - unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; - iread += 1; - } - } - } - - self.cs_mode_word(); - - Ok(words) - } -} - -impl embedded_hal::blocking::spi::Write for Spi { - type Error = Infallible; - - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() {} - - self.cs_mode_frame(); - - let mut iwrite = 0; - let mut iread = 0; - while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { - let byte = unsafe { words.get_unchecked(iwrite) }; - iwrite += 1; - self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); - } - - if iread < iwrite { - // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { - iread += 1; - } - } - } - - self.cs_mode_word(); - - Ok(()) - } -} - -impl embedded_hal::blocking::spi::WriteIter for Spi { - type Error = Infallible; - - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> - where - WI: IntoIterator, - { - let mut iter = words.into_iter(); - - // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() {} - - self.cs_mode_frame(); - - let mut read_count = 0; - let mut has_data = true; - while has_data || read_count > 0 { - if has_data && self.spi.txdata.read().full().bit_is_clear() { - if let Some(byte) = iter.next() { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); - read_count += 1; - } else { - has_data = false; - } - } - - if read_count > 0 { - // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { - read_count -= 1; - } - } - } - - self.cs_mode_word(); - - Ok(()) - } -} - -// Backward compatibility -impl Spi { - /// Configures the SPI peripheral to operate in full duplex master mode - #[deprecated(note = "Please use Spi::new function instead")] - pub fn spi0(spi: QSPI0, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins, - { - Self::new(spi, pins, mode, freq, clocks) - } -} - -impl Spi { - /// Configures the SPI peripheral to operate in full duplex master mode - #[deprecated(note = "Please use Spi::new function instead")] - pub fn spi1(spi: QSPI1, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins, - { - Self::new(spi, pins, mode, freq, clocks) - } -} - -impl Spi { - /// Configures the SPI peripheral to operate in full duplex master mode - #[deprecated(note = "Please use Spi::new function instead")] - pub fn spi2(spi: QSPI2, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks) -> Self - where - PINS: Pins, - { - Self::new(spi, pins, mode, freq, clocks) - } -} +//! +//! # Exclusive Bus usage example +//!``` +//! let pins = (mosi, miso, sck, cs0); +//! let spi_bus = SpiBus::new(p.QSPI1, pins); +//! +//! let spi_config = SpiConfig::new(MODE_0, 100.khz().into(), &clocks); +//! let mut dev = spi_bus.new_device(&spi_config); +//! +//! dev.write(&[1, 2, 3]).unwrap(); +//!``` +//! +//! # Shared Bus usage example +//!``` +//! let pins = (mosi, miso, sck); +//! let spi_bus = SpiBus::shared(p.QSPI1, pins); +//! +//! let spi_config1 = SpiConfig::new(MODE_0, 100.khz().into(), &clocks); +//! let mut dev1 = spi_bus.new_device(cs0, &spi_config1); +//! +//! let spi_config2 = SpiConfig::new(MODE_3, 2.mhz().into(), &clocks); +//! let mut dev2 = spi_bus.new_device(cs1, &spi_config2); +//! +//! dev1.write(&[1, 2, 3]).unwrap(); +//! dev2.write(&[4, 5]).unwrap(); +//!``` + +mod bus; // contains the SPI Bus abstraction +mod config; +mod exclusive_device; // contains the exclusive SPI device abstraction +mod shared_bus; // shared bus newtype +mod shared_device; // contains the shared SPI device abstraction +mod traits; // contains SPI device abstraction + +pub use bus::*; +pub use config::*; +pub use exclusive_device::*; +pub use shared_bus::*; +pub use shared_device::*; +pub use traits::*; diff --git a/src/spi/bus.rs b/src/spi/bus.rs new file mode 100644 index 0000000..94ea72b --- /dev/null +++ b/src/spi/bus.rs @@ -0,0 +1,250 @@ +use core::convert::Infallible; +use embedded_hal::blocking::spi::Operation; +pub use embedded_hal::blocking::spi::{Transfer, Write, WriteIter}; +pub use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; + +use nb; + +use super::{Pins, PinsNoCS, SharedBus, SpiConfig, SpiExclusiveDevice, SpiX}; + +/// SPI bus abstraction +pub struct SpiBus { + pub(crate) spi: SPI, + pub(crate) pins: PINS, +} + +impl SpiBus +where + SPI: SpiX, +{ + /// Construct the [SpiBus] for use with [SpiSharedDevice](super::SpiSharedDevice) or [SpiExclusiveDevice] + pub fn new(spi: SPI, pins: PINS) -> Self + where + PINS: Pins, + { + Self { spi, pins } + } + + /// Releases the SPI peripheral and associated pins + pub fn release(self) -> (SPI, PINS) { + (self.spi, self.pins) + } + + /// Configure the [SpiBus] with given [SpiConfig] + pub(crate) fn configure(&mut self, config: &SpiConfig, cs_index: Option) + where + PINS: Pins, + { + self.spi + .sckdiv + .write(|w| unsafe { w.div().bits(config.clock_divisor as u16) }); + + if let Some(index) = cs_index { + self.spi.csid.write(|w| unsafe { w.bits(index) }); + } + self.spi.csmode.write(|w| w.mode().variant(config.cs_mode)); + + // Set CS pin polarity to high + self.spi.csdef.reset(); + + // Set SPI mode + let phase = config.mode.phase == Phase::CaptureOnSecondTransition; + let polarity = config.mode.polarity == Polarity::IdleHigh; + self.spi + .sckmode + .write(|w| w.pha().bit(phase).pol().bit(polarity)); + + self.spi.fmt.write(|w| unsafe { + w.proto().single(); + w.endian().big(); // Transmit most-significant bit (MSB) first + w.dir().rx(); + w.len().bits(8) + }); + + // Set watermark levels + self.spi + .txmark + .write(|w| unsafe { w.txmark().bits(config.txmark) }); + self.spi + .rxmark + .write(|w| unsafe { w.rxmark().bits(config.rxmark) }); + + // set delays + self.spi.delay0.write(|w| unsafe { + w.cssck().bits(config.delays.cssck); // delay between assert and clock + w.sckcs().bits(config.delays.sckcs) // delay between clock and de-assert + }); + self.spi.delay1.write(|w| unsafe { + w.intercs().bits(config.delays.intercs); // delay between CS re-assets + w.interxfr().bits(config.delays.interxfr) // intra-frame delay without CS re-asserts + }); + + self.end_frame(); // ensure CS is de-asserted before we begin + } + + fn wait_for_rxfifo(&self) { + // Ensure that RX FIFO is empty + while self.spi.rxdata.read().empty().bit_is_clear() {} + } + + /// Starts frame by flagging CS assert, unless CSMODE = OFF + pub(crate) fn start_frame(&mut self) { + if !self.spi.csmode.read().mode().is_off() { + self.spi.csmode.write(|w| w.mode().hold()); + } + } + + /// Finishes frame flagging CS deassert, unless CSMODE = OFF + pub(crate) fn end_frame(&mut self) { + if !self.spi.csmode.read().mode().is_off() { + self.spi.csmode.write(|w| w.mode().auto()); + } + } + + // ex-traits now only accessible via devices + + pub(crate) fn read(&mut self) -> nb::Result { + let rxdata = self.spi.rxdata.read(); + + if rxdata.empty().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + Ok(rxdata.data().bits()) + } + } + + pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + let txdata = self.spi.txdata.read(); + + if txdata.full().bit_is_set() { + Err(nb::Error::WouldBlock) + } else { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + Ok(()) + } + } + + pub(crate) fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Infallible> { + let mut iwrite = 0; + let mut iread = 0; + + // Ensure that RX FIFO is empty + self.wait_for_rxfifo(); + + while iwrite < words.len() || iread < words.len() { + if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = unsafe { words.get_unchecked(iwrite) }; + iwrite += 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + } + + if iread < iwrite { + let data = self.spi.rxdata.read(); + if data.empty().bit_is_clear() { + unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; + iread += 1; + } + } + } + + Ok(words) + } + + pub(crate) fn write(&mut self, words: &[u8]) -> Result<(), Infallible> { + let mut iwrite = 0; + let mut iread = 0; + + // Ensure that RX FIFO is empty + self.wait_for_rxfifo(); + + while iwrite < words.len() || iread < words.len() { + if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = unsafe { words.get_unchecked(iwrite) }; + iwrite += 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + } + + if iread < iwrite { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + iread += 1; + } + } + } + + Ok(()) + } + + pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), Infallible> + where + WI: IntoIterator, + { + let mut iter = words.into_iter(); + + let mut read_count = 0; + let mut has_data = true; + + // Ensure that RX FIFO is empty + self.wait_for_rxfifo(); + + while has_data || read_count > 0 { + if has_data && self.spi.txdata.read().full().bit_is_clear() { + if let Some(byte) = iter.next() { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + read_count += 1; + } else { + has_data = false; + } + } + + if read_count > 0 { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + read_count -= 1; + } + } + } + + Ok(()) + } + + pub(crate) fn exec<'op>( + &mut self, + operations: &mut [Operation<'op, u8>], + ) -> Result<(), Infallible> { + for op in operations { + match op { + Operation::Transfer(words) => { + self.transfer(words)?; + } + Operation::Write(words) => { + self.write(words)?; + } + } + } + + Ok(()) + } +} + +impl SpiBus +where + SPI: SpiX, + PINS: Pins, +{ + /// Create a new [SpiExclusiveDevice] for exclusive use on this bus + pub fn new_device(self, config: &SpiConfig) -> SpiExclusiveDevice { + SpiExclusiveDevice::new(self, config) + } +} + +impl SpiBus +where + SPI: SpiX, + PINS: PinsNoCS, +{ + /// Create a [SharedBus] for use with multiple devices. + pub fn shared(spi: SPI, pins: PINS) -> SharedBus { + SharedBus::new(Self::new(spi, pins)) + } +} diff --git a/src/spi/config.rs b/src/spi/config.rs new file mode 100644 index 0000000..6b30e72 --- /dev/null +++ b/src/spi/config.rs @@ -0,0 +1,69 @@ +use e310x::qspi0::csmode::MODE_A; +use embedded_hal::spi::Mode; + +use crate::{clock::Clocks, time::Hertz}; + +/// SPI Bus configuration + +#[derive(Clone)] +/// SPI Bus configuration +pub struct SpiConfig { + /// SPI Mode + pub mode: Mode, + /// Clock Divisor calculated from frozen core clock frequency and SPI frequency + pub(crate) clock_divisor: u32, + /// CS Mode + pub cs_mode: MODE_A, + /// Watermark level for transmits + pub txmark: u8, + /// Watermark level for received + pub rxmark: u8, + /// Configuration values for CS and SCK related delays + pub delays: SpiDelayConfig, +} + +#[derive(Clone)] +/// Configuration values for CS and SCK related delays +pub struct SpiDelayConfig { + /// delay between assert and clock in clock ticks + pub cssck: u8, + /// delay between clock and de-assert in clock ticks + pub sckcs: u8, + /// delay between CS re-assets in clock ticks + pub intercs: u8, + /// delay between frames when not re-asserting CS in clock ticks + pub interxfr: u8, +} + +impl SpiConfig { + /// Create new default configuration with given [Mode] and frequency using core [Clocks] + pub fn new(mode: Mode, freq: Hertz, clocks: &Clocks) -> Self { + let clock_divisor = clocks.tlclk().0 / (2 * freq.0) - 1; + assert!(clock_divisor <= 0xfff); + + Self { + mode, + clock_divisor, + cs_mode: MODE_A::HOLD, + txmark: 1, + rxmark: 0, + delays: SpiDelayConfig::default(), + } + } + + /// Calculated clock divisor + pub fn clock_divisor(&self) -> u32 { + self.clock_divisor + } +} + +impl Default for SpiDelayConfig { + fn default() -> Self { + Self { + cssck: 1, // 1 cycle delay between CS assert and first clock + sckcs: 1, // 1 cycle delay between last clock and CS de-assert + intercs: 1, // 1 cycle delay between CS re-asserts + interxfr: 0, // no delay intra-frame when not CS re-asserting + } + } +} diff --git a/src/spi/exclusive_device.rs b/src/spi/exclusive_device.rs new file mode 100644 index 0000000..d9e808e --- /dev/null +++ b/src/spi/exclusive_device.rs @@ -0,0 +1,120 @@ +use core::convert::Infallible; + +use embedded_hal::{ + blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, + spi::FullDuplex, +}; + +use crate::spi::SpiConfig; + +use super::{Pins, SpiBus, SpiX}; + +/// SPI exclusive device abstraction +pub struct SpiExclusiveDevice { + bus: SpiBus, +} + +impl SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + /// Create [SpiExclusiveDevice] using the existing [SpiBus](super::SpiBus) + /// with the given [SpiConfig] + pub fn new(mut bus: SpiBus, config: &SpiConfig) -> Self + where + PINS: Pins, + { + bus.configure(config, PINS::CS_INDEX); + + Self { bus } + } + + /// Releases the Bus back deconstructing it + pub fn release(self) -> (SPI, PINS) { + self.bus.release() + } +} + +impl FullDuplex for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + self.bus.read() + } + + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + self.bus.send(byte) + } +} + +impl Transfer for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + type Error = Infallible; + + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + self.bus.start_frame(); + let result = self.bus.transfer(words); + self.bus.end_frame(); + + result + } +} + +impl Write for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + type Error = Infallible; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.bus.start_frame(); + let result = self.bus.write(words); + self.bus.end_frame(); + + result + } +} + +impl WriteIter for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + type Error = Infallible; + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + self.bus.start_frame(); + let result = self.bus.write_iter(words); + self.bus.end_frame(); + + result + } +} + +impl Transactional for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + type Error = Infallible; + + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { + self.bus.start_frame(); + let result = self.bus.exec(operations); + self.bus.end_frame(); + + result + } +} diff --git a/src/spi/shared_bus.rs b/src/spi/shared_bus.rs new file mode 100644 index 0000000..ab10025 --- /dev/null +++ b/src/spi/shared_bus.rs @@ -0,0 +1,70 @@ +use core::cell::RefCell; +use core::ops::Deref; +pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use riscv::interrupt; +use riscv::interrupt::Mutex; + +use super::{PinCS, PinsNoCS, SpiBus, SpiConfig, SpiSharedDevice, SpiX}; + +/// Newtype for RefCell locked behind a Mutex. +/// Used to hold the [SpiBus] instance so it can be used for multiple [SpiSharedDevice] instances. +pub struct SharedBus(Mutex>>); + +impl SharedBus +where + SPI: SpiX, + PINS: PinsNoCS, +{ + pub(crate) fn new(bus: SpiBus) -> Self { + Self(Mutex::new(RefCell::new(bus))) + } + + /// Create a new shared device on this SPI bus. + pub fn new_device<'bus, CS>( + &'bus self, + cs: CS, + config: &SpiConfig, + ) -> SpiSharedDevice<'bus, SPI, PINS, CS> + where + CS: PinCS, + { + SpiSharedDevice::new(self, cs, config) + } +} + +impl SharedBus +where + SPI: SpiX, + PINS: PinsNoCS, +{ + /// Set HOLD CS mode to per-frame operation, unless CSMODE is set to OFF + pub fn start_frame(&mut self) { + interrupt::free(|cs| { + let mut bus = self.0.borrow(*cs).borrow_mut(); + bus.start_frame(); + }); + } + + /// Finishes transfer by deasserting CS (only for hardware-controlled CS) + pub fn end_frame(&mut self) { + interrupt::free(|cs| { + let mut bus = self.0.borrow(*cs).borrow_mut(); + bus.end_frame(); + }); + } + + /// Releases the SPI peripheral and associated pins + pub fn release(self) -> (SPI, PINS) { + let bus = self.0.into_inner().into_inner(); + + (bus.spi, bus.pins) + } +} + +impl Deref for SharedBus { + type Target = Mutex>>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/src/spi/shared_device.rs b/src/spi/shared_device.rs new file mode 100644 index 0000000..e611273 --- /dev/null +++ b/src/spi/shared_device.rs @@ -0,0 +1,165 @@ +use core::convert::Infallible; + +use embedded_hal::{ + blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, + spi::FullDuplex, +}; +use riscv::interrupt; + +use super::{PinCS, Pins, PinsNoCS, SharedBus, SpiConfig, SpiX}; + +/// SPI shared device abstraction +pub struct SpiSharedDevice<'bus, SPI, PINS, CS> { + bus: &'bus SharedBus, + cs: CS, + config: SpiConfig, +} + +impl<'bus, SPI, PINS, CS> SpiSharedDevice<'bus, SPI, PINS, CS> +where + SPI: SpiX, + PINS: PinsNoCS, + CS: PinCS, +{ + /// Create shared [SpiSharedDevice] using the existing [SharedBus] + /// and given [SpiConfig]. The config gets cloned. + pub fn new(bus: &'bus SharedBus, cs: CS, config: &SpiConfig) -> Self + where + PINS: PinsNoCS, + { + Self { + bus, + cs, + config: config.clone(), + } + } + + /// Releases the CS pin back + pub fn release(self) -> CS { + self.cs + } +} + +impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.read() + }) + } + + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.send(byte) + }) + } +} + +impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + type Error = Infallible; + + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + interrupt::free(move |cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.start_frame(); + let result = bus.transfer(words); + bus.end_frame(); + + result + }) + } +} + +impl Write for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + type Error = Infallible; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.start_frame(); + let result = bus.write(words); + bus.end_frame(); + + result + }) + } +} + +impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + type Error = Infallible; + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.start_frame(); + let result = bus.write_iter(words); + bus.end_frame(); + + result + }) + } +} + +impl Transactional for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + type Error = Infallible; + + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.start_frame(); + let result = bus.exec(operations); + bus.end_frame(); + + result + }) + } +} diff --git a/src/spi/traits.rs b/src/spi/traits.rs new file mode 100644 index 0000000..16f91f5 --- /dev/null +++ b/src/spi/traits.rs @@ -0,0 +1,206 @@ +/// Helper traits for SPI pins +use core::ops::Deref; +use e310x::{qspi0, QSPI0, QSPI1, QSPI2}; + +#[doc(hidden)] +pub trait SpiX: Deref + private::Sealed {} +impl SpiX for QSPI0 {} +impl SpiX for QSPI1 {} +impl SpiX for QSPI2 {} + +/// SPI pins - DO NOT IMPLEMENT THIS TRAIT +/// +/// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) and (MOSI, MISO, SCK, CS) +/// and combinations without MOSI/MISO +pub trait Pins: private::Sealed { + #[doc(hidden)] + const CS_INDEX: Option; +} + +/// SPI pins without CS - DO NOT IMPLEMENT THIS TRAIT +/// +/// This trait is implemented for pin tuples (), (MOSI, MISO, SCK) only without CS pin +/// and combinations without MOSI/MISO +pub trait PinsNoCS: Pins {} + +/// SPI Chip Select pin - DO NOT IMPLEMENT THIS TRAIT +/// +/// This trait is implemented for chip select pins only +pub trait PinCS: private::Sealed { + #[doc(hidden)] + const CS_INDEX: u32; +} + +/* SPI0 pins */ +impl Pins for () { + const CS_INDEX: Option = Some(0); +} + +/* SPI1 pins */ +mod spi1_impl { + use super::{PinCS, Pins, PinsNoCS, QSPI1}; + use crate::gpio::gpio0; + use crate::gpio::{NoInvert, IOF0}; + + type MOSI = gpio0::Pin3>; + type MISO = gpio0::Pin4>; + type SCK = gpio0::Pin5>; + type CS0 = gpio0::Pin2>; + type CS1 = gpio0::Pin8>; + type CS2 = gpio0::Pin9>; + type CS3 = gpio0::Pin10>; + + // ensure only the correct CS pins can be used to make SpiSharedDevice instances + impl PinCS for CS0 { + const CS_INDEX: u32 = 0; + } + impl PinCS for CS1 { + const CS_INDEX: u32 = 1; + } + impl PinCS for CS2 { + const CS_INDEX: u32 = 2; + } + impl PinCS for CS3 { + const CS_INDEX: u32 = 3; + } + + impl PinsNoCS for (MOSI, MISO, SCK) {} + impl PinsNoCS for (MOSI, (), SCK) {} + impl PinsNoCS for ((), MISO, SCK) {} + + impl Pins for (MOSI, MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, (), SCK) { + const CS_INDEX: Option = None; + } + impl Pins for ((), MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, MISO, SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, (), SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for ((), MISO, SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, MISO, SCK, CS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for (MOSI, (), SCK, CS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for ((), MISO, SCK, CS1) { + const CS_INDEX: Option = Some(1); + } + impl Pins for (MOSI, MISO, SCK, CS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for (MOSI, (), SCK, CS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for ((), MISO, SCK, CS2) { + const CS_INDEX: Option = Some(2); + } + impl Pins for (MOSI, MISO, SCK, CS3) { + const CS_INDEX: Option = Some(3); + } + impl Pins for (MOSI, (), SCK, CS3) { + const CS_INDEX: Option = Some(3); + } + impl Pins for ((), MISO, SCK, CS3) { + const CS_INDEX: Option = Some(3); + } + + // seal the "private" traits + mod spi1_private { + use super::super::private::Sealed; + use super::*; + + impl Sealed for CS0 {} + impl Sealed for CS1 {} + impl Sealed for CS2 {} + impl Sealed for CS3 {} + impl Sealed for (MOSI, MISO, SCK) {} + impl Sealed for (MOSI, (), SCK) {} + impl Sealed for ((), MISO, SCK) {} + impl Sealed for (MOSI, MISO, SCK, CS0) {} + impl Sealed for (MOSI, (), SCK, CS0) {} + impl Sealed for ((), MISO, SCK, CS0) {} + impl Sealed for (MOSI, MISO, SCK, CS1) {} + impl Sealed for (MOSI, (), SCK, CS1) {} + impl Sealed for ((), MISO, SCK, CS1) {} + impl Sealed for (MOSI, MISO, SCK, CS2) {} + impl Sealed for (MOSI, (), SCK, CS2) {} + impl Sealed for ((), MISO, SCK, CS2) {} + impl Sealed for (MOSI, MISO, SCK, CS3) {} + impl Sealed for (MOSI, (), SCK, CS3) {} + impl Sealed for ((), MISO, SCK, CS3) {} + } +} + +/* SPI2 pins */ +mod spi2_impl { + use super::{PinCS, Pins, PinsNoCS, QSPI2}; + use crate::gpio::gpio0; + use crate::gpio::{NoInvert, IOF0}; + + type MOSI = gpio0::Pin27>; + type MISO = gpio0::Pin28>; + type SCK = gpio0::Pin29>; + type CS0 = gpio0::Pin26>; + + impl PinCS for CS0 { + const CS_INDEX: u32 = 0; + } + + impl PinsNoCS for (MOSI, MISO, SCK) {} + impl PinsNoCS for (MOSI, (), SCK) {} + impl PinsNoCS for ((), MISO, SCK) {} + + impl Pins for (MOSI, MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, (), SCK) { + const CS_INDEX: Option = None; + } + impl Pins for ((), MISO, SCK) { + const CS_INDEX: Option = None; + } + impl Pins for (MOSI, MISO, SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for (MOSI, (), SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + impl Pins for ((), MISO, SCK, CS0) { + const CS_INDEX: Option = Some(0); + } + + // seal the "private" traits + mod spi2_private { + use super::super::private::Sealed; + use super::*; + + impl Sealed for CS0 {} + impl Sealed for (MOSI, MISO, SCK) {} + impl Sealed for (MOSI, (), SCK) {} + impl Sealed for ((), MISO, SCK) {} + impl Sealed for (MOSI, MISO, SCK, CS0) {} + impl Sealed for (MOSI, (), SCK, CS0) {} + impl Sealed for ((), MISO, SCK, CS0) {} + } +} + +// seal the "private" traits +mod private { + pub trait Sealed {} + + impl Sealed for () {} + + impl Sealed for super::QSPI0 {} + impl Sealed for super::QSPI1 {} + impl Sealed for super::QSPI2 {} +} From a96104aa929449df7f1668534aed80d588a18f14 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Thu, 3 Mar 2022 15:06:20 -0800 Subject: [PATCH 261/315] Update embedded-hal dependency to 1.0.0-alpha.7 --- Cargo.toml | 4 +- src/delay.rs | 107 +------------ src/gpio.rs | 31 ++-- src/i2c.rs | 290 +++++++++++++++++++++++++++++++----- src/prelude.rs | 3 +- src/serial.rs | 19 ++- src/spi/bus.rs | 58 ++++++-- src/spi/exclusive_device.rs | 69 ++++++--- src/spi/shared_device.rs | 83 ++++++++--- src/stdout.rs | 6 +- 10 files changed, 442 insertions(+), 228 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a9c9144..372b68a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = "=1.0.0-alpha.1" +embedded-hal = "=1.0.0-alpha.7" nb = "1.0.0" -riscv = "0.7.0" +riscv = "=0.8.0-alpha.7" e310x = { version = "0.9.0", features = ["rt"] } [features] diff --git a/src/delay.rs b/src/delay.rs index 58fc711..30b42e6 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -3,7 +3,7 @@ use crate::clock::Clocks; use crate::core::clint::{MTIME, MTIMECMP}; use core::convert::Infallible; -use embedded_hal::blocking::delay::{DelayMs, DelayUs}; +use embedded_hal::delay::blocking::DelayUs; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider @@ -18,10 +18,10 @@ impl Delay { } } -impl DelayUs for Delay { +impl DelayUs for Delay { type Error = Infallible; - fn try_delay_us(&mut self, us: u32) -> Result<(), Infallible> { + fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { let ticks = (us as u64) * TICKS_PER_SECOND / 1_000_000; let mtime = MTIME; @@ -31,72 +31,6 @@ impl DelayUs for Delay { } } -// This is a workaround to allow `delay_us(42)` construction without specifying a type. -impl DelayUs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_us(&mut self, us: i32) -> Result<(), Infallible> { - assert!(us >= 0); - self.try_delay_us(us as u32) - } -} - -impl DelayUs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_us(&mut self, us: u16) -> Result<(), Infallible> { - self.try_delay_us(u32::from(us)) - } -} - -impl DelayUs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_us(&mut self, us: u8) -> Result<(), Infallible> { - self.try_delay_us(u32::from(us)) - } -} - -impl DelayMs for Delay { - type Error = Infallible; - - fn try_delay_ms(&mut self, ms: u32) -> Result<(), Infallible> { - self.try_delay_us(ms * 1000) - } -} - -// This is a workaround to allow `delay_ms(42)` construction without specifying a type. -impl DelayMs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: i32) -> Result<(), Infallible> { - assert!(ms >= 0); - self.try_delay_ms(ms as u32) - } -} - -impl DelayMs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: u16) -> Result<(), Infallible> { - self.try_delay_ms(u32::from(ms)) - } -} - -impl DelayMs for Delay { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: u8) -> Result<(), Infallible> { - self.try_delay_ms(u32::from(ms)) - } -} - /// Machine timer (mtime) as a sleep delay provider using mtimecmp pub struct Sleep { clock_freq: u32, @@ -113,11 +47,11 @@ impl Sleep { } } -impl DelayMs for Sleep { +impl DelayUs for Sleep { type Error = Infallible; - fn try_delay_ms(&mut self, ms: u32) -> Result<(), Infallible> { - let ticks = (ms as u64) * (self.clock_freq as u64) / 1000; + fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { + let ticks = (us as u64) * (self.clock_freq as u64) / 1_000_000; let t = MTIME.mtime() + ticks; self.mtimecmp.set_mtimecmp(t); @@ -150,32 +84,3 @@ impl DelayMs for Sleep { Ok(()) } } - -// This is a workaround to allow `delay_ms(42)` construction without specifying a type. -impl DelayMs for Sleep { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: i32) -> Result<(), Infallible> { - assert!(ms >= 0); - self.try_delay_ms(ms as u32) - } -} - -impl DelayMs for Sleep { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: u16) -> Result<(), Infallible> { - self.try_delay_ms(u32::from(ms)) - } -} - -impl DelayMs for Sleep { - type Error = Infallible; - - #[inline(always)] - fn try_delay_ms(&mut self, ms: u8) -> Result<(), Infallible> { - self.try_delay_ms(u32::from(ms)) - } -} diff --git a/src/gpio.rs b/src/gpio.rs index c38f4ae..be0b294 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -142,7 +142,8 @@ macro_rules! gpio { use core::marker::PhantomData; use core::convert::Infallible; - use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::ErrorType; + use embedded_hal::digital::blocking::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::$GPIOX; use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, @@ -275,48 +276,50 @@ macro_rules! gpio { } } - impl InputPin for $PXi> { + impl ErrorType for $PXi> { type Error = Infallible; + } - fn try_is_high(&self) -> Result { + impl InputPin for $PXi> { + fn is_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) } - fn try_is_low(&self) -> Result { - Ok(!self.try_is_high()?) + fn is_low(&self) -> Result { + Ok(!self.is_high()?) } } impl StatefulOutputPin for $PXi> { - fn try_is_set_high(&self) -> Result { + fn is_set_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) } - fn try_is_set_low(&self) -> Result { - Ok(!self.try_is_set_high()?) + fn is_set_low(&self) -> Result { + Ok(!self.is_set_high()?) } } - impl OutputPin for $PXi> { + impl ErrorType for $PXi> { type Error = Infallible; + } - fn try_set_high(&mut self) -> Result<(), Infallible> { + impl OutputPin for $PXi> { + fn set_high(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, true); Ok(()) } - fn try_set_low(&mut self) -> Result<(), Infallible> { + fn set_low(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, false); Ok(()) } } impl ToggleableOutputPin for $PXi> { - type Error = Infallible; - /// Toggles the pin state. - fn try_toggle(&mut self) -> Result<(), Infallible> { + fn toggle(&mut self) -> Result<(), Infallible> { $GPIOX::toggle_pin(Self::INDEX); Ok(()) } diff --git a/src/i2c.rs b/src/i2c.rs index 54bad55..e0e049a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -16,7 +16,8 @@ use crate::time::Bps; use core::mem; use core::ops::Deref; use e310x::{i2c0, I2C0}; -use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; +use embedded_hal::i2c::blocking::{self as i2c, Operation}; +use embedded_hal::i2c::{ErrorKind, ErrorType, NoAcknowledgeSource}; /// SDA pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait SdaPin {} @@ -26,19 +27,6 @@ pub unsafe trait SclPin {} unsafe impl SdaPin for gpio0::Pin12> {} unsafe impl SclPin for gpio0::Pin13> {} -/// I2C error -#[derive(Debug, Eq, PartialEq)] -pub enum Error { - /// Invalid peripheral state - InvalidState, - - /// Arbitration lost - ArbitrationLost, - - /// No ACK received - NoAck, -} - /// Transmission speed pub enum Speed { /// 100Kbps @@ -121,7 +109,7 @@ impl, PINS> I2c { } fn read_sr(&self) -> i2c0::sr::R { - unsafe { mem::transmute(self.i2c.sr().read()) } + self.i2c.sr().read() } fn write_byte(&self, byte: u8) { @@ -132,7 +120,7 @@ impl, PINS> I2c { self.i2c.txr_rxr.read().data().bits() } - fn wait_for_interrupt(&self) -> Result<(), Error> { + fn wait_for_interrupt(&self) -> Result<(), ErrorKind> { loop { let sr = self.read_sr(); @@ -141,7 +129,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(Error::ArbitrationLost); + return Err(ErrorKind::ArbitrationLoss); } if sr.if_().bit_is_set() { @@ -153,11 +141,11 @@ impl, PINS> I2c { } } - fn wait_for_read(&self) -> Result<(), Error> { + fn wait_for_read(&self) -> Result<(), ErrorKind> { self.wait_for_interrupt() } - fn wait_for_write(&self) -> Result<(), Error> { + fn wait_for_write(&self) -> Result<(), ErrorKind> { self.wait_for_interrupt()?; if self.read_sr().rx_ack().bit_is_set() { @@ -165,7 +153,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(Error::NoAck); + return Err(ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown)); } Ok(()) @@ -179,14 +167,16 @@ impl, PINS> I2c { const FLAG_READ: u8 = 1; const FLAG_WRITE: u8 = 0; -impl, PINS> Read for I2c { - type Error = Error; +impl ErrorType for I2c { + type Error = ErrorKind; +} - fn try_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { +impl, PINS> i2c::I2c for I2c { + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(Error::InvalidState); + return Err(ErrorKind::Other); } // Write address + R @@ -212,16 +202,12 @@ impl, PINS> Read for I2c { } Ok(()) } -} -impl, PINS> Write for I2c { - type Error = Error; - - fn try_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(Error::InvalidState); + return Err(ErrorKind::Other); } // Write address + W @@ -244,12 +230,41 @@ impl, PINS> Write for I2c { } Ok(()) } -} -impl, PINS> WriteRead for I2c { - type Error = Error; + fn write_iter>( + &mut self, + address: u8, + bytes: B, + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } - fn try_write_read( + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + let mut bytes = bytes.into_iter().peekable(); + while let Some(byte) = bytes.next() { + self.write_byte(byte); + + if bytes.peek().is_some() { + self.write_cr(|w| w.wr().set_bit()); // all others + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); // last one + } + self.wait_for_write()?; + } + Ok(()) + } + + fn write_read( &mut self, address: u8, bytes: &[u8], @@ -258,13 +273,13 @@ impl, PINS> WriteRead for I2c, PINS> WriteRead for I2c>( + &mut self, + address: u8, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let mut bytes = bytes.into_iter().peekable(); + if bytes.peek().is_some() && buffer.is_empty() { + self.write_iter(address, bytes) + } else if !buffer.is_empty() && bytes.peek().is_none() { + self.read(address, buffer) + } else if bytes.peek().is_none() && buffer.is_empty() { + Ok(()) + } else { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + for byte in bytes { + self.write_byte(byte); + + self.write_cr(|w| w.wr().set_bit()); + self.wait_for_write()?; + } + + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Read bytes + let buffer_len = buffer.len(); + for (i, byte) in buffer.iter_mut().enumerate() { + if i != buffer_len - 1 { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + + Ok(()) + } + } + + fn transaction<'a>( + &mut self, + address: u8, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let last_op = operations.len() - 1; + let mut last_flag = 0xFF; + for (i, op) in operations.iter_mut().enumerate() { + match op { + Operation::Read(bytes) => { + if last_flag != FLAG_READ { + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_READ; + } + + // Read bytes + let last_byte = bytes.len() - 1; + for (j, byte) in bytes.iter_mut().enumerate() { + if i != last_op || j != last_byte { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + } + Operation::Write(bytes) => { + if last_flag != FLAG_WRITE { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_WRITE; + } + + // Write bytes + for (j, byte) in bytes.iter().enumerate() { + self.write_byte(*byte); + + if i != last_op || j != bytes.len() - 1 { + self.write_cr(|w| w.wr().set_bit()); + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); + } + self.wait_for_write()?; + } + } + } + } + + Ok(()) + } + + fn transaction_iter<'a, O: IntoIterator>>( + &mut self, + address: u8, + operations: O, + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let mut last_flag = 0xFF; + let mut operations = operations.into_iter().peekable(); + while let Some(op) = operations.next() { + match op { + Operation::Read(bytes) => { + if last_flag != FLAG_READ { + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_READ; + } + + // Read bytes + let last_byte = bytes.len() - 1; + for (j, byte) in bytes.iter_mut().enumerate() { + if operations.peek().is_some() || j != last_byte { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + } + Operation::Write(bytes) => { + if last_flag != FLAG_WRITE { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_WRITE; + } + + // Write bytes + for (j, byte) in bytes.iter().enumerate() { + self.write_byte(*byte); + + if operations.peek().is_some() || j != bytes.len() - 1 { + self.write_cr(|w| w.wr().set_bit()); + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); + } + self.wait_for_write()?; + } + } + } + } + + Ok(()) + } } diff --git a/src/prelude.rs b/src/prelude.rs index d066f0e..a26b75f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,5 +7,4 @@ pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; -pub use embedded_hal::digital::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin; -pub use embedded_hal::prelude::*; +pub use embedded_hal::digital::blocking::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin; diff --git a/src/serial.rs b/src/serial.rs index 697931f..c88c2ac 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -13,7 +13,6 @@ //! - RX: Pin 23 IOF0 //! - Interrupt::UART1 -use core::convert::Infallible; use core::ops::Deref; use embedded_hal::serial; @@ -114,10 +113,12 @@ impl Serial { } } -impl serial::Read for Rx { - type Error = Infallible; +impl serial::ErrorType for Rx { + type Error = serial::ErrorKind; +} - fn try_read(&mut self) -> nb::Result { +impl serial::nb::Read for Rx { + fn read(&mut self) -> nb::Result { let rxdata = self.uart.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -128,10 +129,12 @@ impl serial::Read for Rx { } } -impl serial::Write for Tx { - type Error = Infallible; +impl serial::ErrorType for Tx { + type Error = serial::ErrorKind; +} - fn try_write(&mut self, byte: u8) -> nb::Result<(), Infallible> { +impl serial::nb::Write for Tx { + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { let txdata = self.uart.txdata.read(); if txdata.full().bit_is_set() { @@ -144,7 +147,7 @@ impl serial::Write for Tx { } } - fn try_flush(&mut self) -> nb::Result<(), Infallible> { + fn flush(&mut self) -> nb::Result<(), Self::Error> { if self.uart.ip.read().txwm().bit_is_set() { // FIFO count is below the receive watermark (1) Ok(()) diff --git a/src/spi/bus.rs b/src/spi/bus.rs index 2a8f301..b72bdf5 100644 --- a/src/spi/bus.rs +++ b/src/spi/bus.rs @@ -1,6 +1,7 @@ -use core::convert::Infallible; -pub use embedded_hal::blocking::spi::{Transfer, Write, WriteIter}; -pub use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use embedded_hal::spi::blocking::Operation; +pub use embedded_hal::spi::blocking::{Read, Transfer, TransferInplace, Write, WriteIter}; +pub use embedded_hal::spi::nb::FullDuplex; +pub use embedded_hal::spi::{ErrorKind, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use nb; @@ -102,7 +103,7 @@ where // ex-traits now only accessible via devices - pub(crate) fn read(&mut self) -> nb::Result { + pub(crate) fn read(&mut self) -> nb::Result { let rxdata = self.spi.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -112,7 +113,7 @@ where } } - pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), ErrorKind> { let txdata = self.spi.txdata.read(); if txdata.full().bit_is_set() { @@ -123,16 +124,16 @@ where } } - pub(crate) fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Infallible> { + pub(crate) fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), ErrorKind> { let mut iwrite = 0; let mut iread = 0; // Ensure that RX FIFO is empty self.wait_for_rxfifo(); - while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { - let byte = unsafe { words.get_unchecked(iwrite) }; + while iwrite < write.len() || iread < read.len() { + if iread < read.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = write.get(iwrite).unwrap_or(&0); iwrite += 1; self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); } @@ -140,16 +141,18 @@ where if iread < iwrite { let data = self.spi.rxdata.read(); if data.empty().bit_is_clear() { - unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; + if let Some(d) = read.get_mut(iread) { + *d = data.data().bits() + }; iread += 1; } } } - Ok(words) + Ok(()) } - pub(crate) fn write(&mut self, words: &[u8]) -> Result<(), Infallible> { + pub(crate) fn transfer_inplace(&mut self, words: &mut [u8]) -> Result<(), ErrorKind> { let mut iwrite = 0; let mut iread = 0; @@ -164,8 +167,9 @@ where } if iread < iwrite { - // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { + let data = self.spi.rxdata.read(); + if data.empty().bit_is_clear() { + unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; iread += 1; } } @@ -174,7 +178,7 @@ where Ok(()) } - pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), Infallible> + pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), ErrorKind> where WI: IntoIterator, { @@ -206,6 +210,30 @@ where Ok(()) } + + pub(crate) fn exec<'op>( + &mut self, + operations: &mut [Operation<'op, u8>], + ) -> Result<(), ErrorKind> { + for op in operations { + match op { + Operation::Read(words) => { + self.transfer(words, &[])?; + } + Operation::Write(words) => { + self.transfer(&mut [], words)?; + } + Operation::Transfer(read_words, write_words) => { + self.transfer(read_words, write_words)?; + } + Operation::TransferInplace(words) => { + self.transfer_inplace(words)?; + } + } + } + + Ok(()) + } } impl SpiBus diff --git a/src/spi/exclusive_device.rs b/src/spi/exclusive_device.rs index e732f45..367ac15 100644 --- a/src/spi/exclusive_device.rs +++ b/src/spi/exclusive_device.rs @@ -1,8 +1,7 @@ -use core::convert::Infallible; - -use embedded_hal::{ - blocking::spi::{Transfer, Write, WriteIter}, - spi::FullDuplex, +use embedded_hal::spi::{ + blocking::{Operation, Transactional, Transfer, TransferInplace, Write, WriteIter}, + nb::FullDuplex, + ErrorKind, ErrorType, }; use crate::spi::SpiConfig; @@ -36,62 +35,72 @@ where } } -impl FullDuplex for SpiExclusiveDevice +impl ErrorType for SpiExclusiveDevice { + type Error = ErrorKind; +} + +impl FullDuplex for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - type Error = Infallible; - - fn try_read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { self.bus.read() } - fn try_send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { self.bus.send(byte) } } -impl Transfer for SpiExclusiveDevice +impl Transfer for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - type Error = Infallible; - - fn try_transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { self.bus.start_frame(); - let result = self.bus.transfer(words); + let result = self.bus.transfer(read, write); self.bus.end_frame(); result } } -impl Write for SpiExclusiveDevice +impl TransferInplace for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - type Error = Infallible; - - fn try_write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + fn transfer_inplace<'w>(&mut self, words: &'w mut [u8]) -> Result<(), Self::Error> { self.bus.start_frame(); - let result = self.bus.write(words); + let result = self.bus.transfer_inplace(words); self.bus.end_frame(); result } } -impl WriteIter for SpiExclusiveDevice +impl Write for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - type Error = Infallible; + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.bus.start_frame(); + let result = self.bus.transfer(&mut [], words); + self.bus.end_frame(); - fn try_write_iter(&mut self, words: WI) -> Result<(), Self::Error> + result + } +} + +impl WriteIter for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, { @@ -102,3 +111,17 @@ where result } } + +impl Transactional for SpiExclusiveDevice +where + SPI: SpiX, + PINS: Pins, +{ + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Self::Error> { + self.bus.start_frame(); + let result = self.bus.exec(operations); + self.bus.end_frame(); + + result + } +} diff --git a/src/spi/shared_device.rs b/src/spi/shared_device.rs index e96d498..bf6c53d 100644 --- a/src/spi/shared_device.rs +++ b/src/spi/shared_device.rs @@ -1,8 +1,7 @@ -use core::convert::Infallible; - -use embedded_hal::{ - blocking::spi::{Transfer, Write, WriteIter}, - spi::FullDuplex, +use embedded_hal::spi::{ + blocking::{Operation, Transactional, Transfer, TransferInplace, Write, WriteIter}, + nb::FullDuplex, + ErrorKind, ErrorType, }; use riscv::interrupt; @@ -40,15 +39,17 @@ where } } -impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> +impl ErrorType for SpiSharedDevice<'_, SPI, PINS, CS> { + type Error = ErrorKind; +} + +impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - type Error = Infallible; - - fn try_read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); @@ -58,7 +59,7 @@ where }) } - fn try_send(&mut self, byte: u8) -> nb::Result<(), Infallible> { + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); @@ -69,22 +70,20 @@ where } } -impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> +impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - type Error = Infallible; - - fn try_transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { interrupt::free(move |cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); bus.start_frame(); - let result = bus.transfer(words); + let result = bus.transfer(read, write); bus.end_frame(); result @@ -92,22 +91,41 @@ where } } -impl Write for SpiSharedDevice<'_, SPI, PINS, CS> +impl TransferInplace for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - type Error = Infallible; + fn transfer_inplace<'w>(&mut self, words: &'w mut [u8]) -> Result<(), Self::Error> { + interrupt::free(move |cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); - fn try_write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + bus.start_frame(); + let result = bus.transfer_inplace(words); + bus.end_frame(); + + result + }) + } +} + +impl Write for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); bus.start_frame(); - let result = bus.write(words); + let result = bus.transfer(&mut [], words); bus.end_frame(); result @@ -115,15 +133,13 @@ where } } -impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> +impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - type Error = Infallible; - - fn try_write_iter(&mut self, words: WI) -> Result<(), Self::Error> + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, { @@ -140,3 +156,24 @@ where }) } } + +impl Transactional for SpiSharedDevice<'_, SPI, PINS, CS> +where + SPI: SpiX, + PINS: Pins, + CS: PinCS, +{ + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Self::Error> { + interrupt::free(|cs| { + let mut bus = self.bus.borrow(*cs).borrow_mut(); + + bus.configure(&self.config, Some(CS::CS_INDEX)); + + bus.start_frame(); + let result = bus.exec(operations); + bus.end_frame(); + + result + }) + } +} diff --git a/src/stdout.rs b/src/stdout.rs index 0a41699..516a280 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -10,19 +10,19 @@ where impl<'p, T> Write for Stdout<'p, T> where - T: embedded_hal::serial::Write, + T: embedded_hal::serial::nb::Write, { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { if *byte == b'\n' { - let res = block!(self.0.try_write(b'\r')); + let res = block!(self.0.write(b'\r')); if res.is_err() { return Err(::core::fmt::Error); } } - let res = block!(self.0.try_write(*byte)); + let res = block!(self.0.write(*byte)); if res.is_err() { return Err(::core::fmt::Error); From 7d3c5158a1f668cd3b29be71f24d2ed72e463dd8 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 20 Jun 2022 10:00:45 -0700 Subject: [PATCH 262/315] use riscv v0.8.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 372b68a..ebbb8ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] embedded-hal = "=1.0.0-alpha.7" nb = "1.0.0" -riscv = "=0.8.0-alpha.7" +riscv = "0.8.0" e310x = { version = "0.9.0", features = ["rt"] } [features] From e4592f9d5d13474976501e76a4a54712e04ddbc1 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 20 Jun 2022 10:01:14 -0700 Subject: [PATCH 263/315] bump version to v0.10.0-alpha.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ebbb8ad..e181efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.3" +version = "0.10.0-alpha.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] From aab090b910e1b3e505e3f0e642ac48dbc1b98e1e Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 20 Jun 2022 10:05:14 -0700 Subject: [PATCH 264/315] bump MSRV --- .github/bors.toml | 2 +- .github/workflows/ci.yaml | 4 ++-- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index b5b4935..5f39ccb 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -3,7 +3,7 @@ delete_merged_branches = true required_approvals = 1 status = [ "ci-linux (stable)", - "ci-linux (1.42.0)", + "ci-linux (1.54.0)", "build-other (macOS-latest)", "build-other (windows-latest)", "Rustfmt" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2addd1a..c9800ae 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.42.0 - rust: [nightly, stable, 1.42.0] + # All generated code should be running on stable now, MRSV is 1.54.0 + rust: [nightly, stable, 1.54.0] include: # Nightly is only for reference and allowed to fail diff --git a/README.md b/README.md index 81455da..b902303 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.54.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License From 648aa58904803f35985aa3e4780ca02186632faa Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 20 Jun 2022 12:21:09 -0700 Subject: [PATCH 265/315] bump MSRV to 1.59 due to asm! macro --- .github/bors.toml | 2 +- .github/workflows/ci.yaml | 4 ++-- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index 5f39ccb..ca7d72a 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -3,7 +3,7 @@ delete_merged_branches = true required_approvals = 1 status = [ "ci-linux (stable)", - "ci-linux (1.54.0)", + "ci-linux (1.59.0)", "build-other (macOS-latest)", "build-other (windows-latest)", "Rustfmt" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c9800ae..4366937 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.54.0 - rust: [nightly, stable, 1.54.0] + # All generated code should be running on stable now, MRSV is 1.59.0 + rust: [nightly, stable, 1.59.0] include: # Nightly is only for reference and allowed to fail diff --git a/README.md b/README.md index b902303..bf2f875 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.54.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License From c7e37ab1bb501805a3fa3c73b9bbb3319c0eaab2 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 23 Jun 2022 14:05:46 -0700 Subject: [PATCH 266/315] fix SpiBus::transfer logic --- src/spi/bus.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spi/bus.rs b/src/spi/bus.rs index b72bdf5..921d74b 100644 --- a/src/spi/bus.rs +++ b/src/spi/bus.rs @@ -132,7 +132,7 @@ where self.wait_for_rxfifo(); while iwrite < write.len() || iread < read.len() { - if iread < read.len() && self.spi.txdata.read().full().bit_is_clear() { + if iwrite < write.len() && self.spi.txdata.read().full().bit_is_clear() { let byte = write.get(iwrite).unwrap_or(&0); iwrite += 1; self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); From 0b5c86968f8e7c9d944d28af26de809a8dbaaec3 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 25 Jun 2022 09:57:16 -0700 Subject: [PATCH 267/315] Revert PR #42 and following fixups --- .github/bors.toml | 2 +- .github/workflows/ci.yaml | 4 +- Cargo.toml | 6 +- README.md | 2 +- src/delay.rs | 93 ++++++++++-- src/gpio.rs | 13 +- src/i2c.rs | 280 +++++------------------------------- src/prelude.rs | 7 +- src/serial.rs | 19 ++- src/spi.rs | 4 +- src/spi/bus.rs | 49 +++---- src/spi/exclusive_device.rs | 57 ++++---- src/spi/shared_device.rs | 64 ++++----- src/stdout.rs | 2 +- 14 files changed, 211 insertions(+), 391 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index ca7d72a..b5b4935 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -3,7 +3,7 @@ delete_merged_branches = true required_approvals = 1 status = [ "ci-linux (stable)", - "ci-linux (1.59.0)", + "ci-linux (1.42.0)", "build-other (macOS-latest)", "build-other (windows-latest)", "Rustfmt" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4366937..2addd1a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.59.0 - rust: [nightly, stable, 1.59.0] + # All generated code should be running on stable now, MRSV is 1.42.0 + rust: [nightly, stable, 1.42.0] include: # Nightly is only for reference and allowed to fail diff --git a/Cargo.toml b/Cargo.toml index e181efa..e79aed9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.10.0-alpha.1" +version = "0.9.3" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -10,9 +10,9 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = "=1.0.0-alpha.7" +embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -riscv = "0.8.0" +riscv = "0.7.0" e310x = { version = "0.9.0", features = ["rt"] } [features] diff --git a/README.md b/README.md index bf2f875..81455da 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/src/delay.rs b/src/delay.rs index 30b42e6..4778bf1 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -2,8 +2,7 @@ use crate::clock::Clocks; use crate::core::clint::{MTIME, MTIMECMP}; -use core::convert::Infallible; -use embedded_hal::delay::blocking::DelayUs; +use embedded_hal::blocking::delay::{DelayMs, DelayUs}; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider @@ -18,16 +17,65 @@ impl Delay { } } -impl DelayUs for Delay { - type Error = Infallible; - - fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { +impl DelayUs for Delay { + fn delay_us(&mut self, us: u32) { let ticks = (us as u64) * TICKS_PER_SECOND / 1_000_000; let mtime = MTIME; let t = mtime.mtime() + ticks; while mtime.mtime() < t {} - Ok(()) + } +} + +// This is a workaround to allow `delay_us(42)` construction without specifying a type. +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: i32) { + assert!(us >= 0); + self.delay_us(us as u32); + } +} + +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: u16) { + self.delay_us(u32::from(us)); + } +} + +impl DelayUs for Delay { + #[inline(always)] + fn delay_us(&mut self, us: u8) { + self.delay_us(u32::from(us)); + } +} + +impl DelayMs for Delay { + fn delay_ms(&mut self, ms: u32) { + self.delay_us(ms * 1000); + } +} + +// This is a workaround to allow `delay_ms(42)` construction without specifying a type. +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: i32) { + assert!(ms >= 0); + self.delay_ms(ms as u32); + } +} + +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: u16) { + self.delay_ms(u32::from(ms)); + } +} + +impl DelayMs for Delay { + #[inline(always)] + fn delay_ms(&mut self, ms: u8) { + self.delay_ms(u32::from(ms)); } } @@ -47,11 +95,9 @@ impl Sleep { } } -impl DelayUs for Sleep { - type Error = Infallible; - - fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { - let ticks = (us as u64) * (self.clock_freq as u64) / 1_000_000; +impl DelayMs for Sleep { + fn delay_ms(&mut self, ms: u32) { + let ticks = (ms as u64) * (self.clock_freq as u64) / 1000; let t = MTIME.mtime() + ticks; self.mtimecmp.set_mtimecmp(t); @@ -80,7 +126,28 @@ impl DelayUs for Sleep { unsafe { mie::clear_mtimer(); } + } +} + +// This is a workaround to allow `delay_ms(42)` construction without specifying a type. +impl DelayMs for Sleep { + #[inline(always)] + fn delay_ms(&mut self, ms: i32) { + assert!(ms >= 0); + self.delay_ms(ms as u32); + } +} + +impl DelayMs for Sleep { + #[inline(always)] + fn delay_ms(&mut self, ms: u16) { + self.delay_ms(u32::from(ms)); + } +} - Ok(()) +impl DelayMs for Sleep { + #[inline(always)] + fn delay_ms(&mut self, ms: u8) { + self.delay_ms(u32::from(ms)); } } diff --git a/src/gpio.rs b/src/gpio.rs index be0b294..63239f0 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -142,8 +142,7 @@ macro_rules! gpio { use core::marker::PhantomData; use core::convert::Infallible; - use embedded_hal::digital::ErrorType; - use embedded_hal::digital::blocking::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::$GPIOX; use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, @@ -276,11 +275,9 @@ macro_rules! gpio { } } - impl ErrorType for $PXi> { + impl InputPin for $PXi> { type Error = Infallible; - } - impl InputPin for $PXi> { fn is_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) @@ -301,11 +298,9 @@ macro_rules! gpio { } } - impl ErrorType for $PXi> { + impl OutputPin for $PXi> { type Error = Infallible; - } - impl OutputPin for $PXi> { fn set_high(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, true); Ok(()) @@ -318,6 +313,8 @@ macro_rules! gpio { } impl ToggleableOutputPin for $PXi> { + type Error = Infallible; + /// Toggles the pin state. fn toggle(&mut self) -> Result<(), Infallible> { $GPIOX::toggle_pin(Self::INDEX); diff --git a/src/i2c.rs b/src/i2c.rs index e0e049a..d969add 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -16,8 +16,7 @@ use crate::time::Bps; use core::mem; use core::ops::Deref; use e310x::{i2c0, I2C0}; -use embedded_hal::i2c::blocking::{self as i2c, Operation}; -use embedded_hal::i2c::{ErrorKind, ErrorType, NoAcknowledgeSource}; +use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; /// SDA pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait SdaPin {} @@ -27,6 +26,19 @@ pub unsafe trait SclPin {} unsafe impl SdaPin for gpio0::Pin12> {} unsafe impl SclPin for gpio0::Pin13> {} +/// I2C error +#[derive(Debug, Eq, PartialEq)] +pub enum Error { + /// Invalid peripheral state + InvalidState, + + /// Arbitration lost + ArbitrationLost, + + /// No ACK received + NoAck, +} + /// Transmission speed pub enum Speed { /// 100Kbps @@ -109,7 +121,7 @@ impl, PINS> I2c { } fn read_sr(&self) -> i2c0::sr::R { - self.i2c.sr().read() + unsafe { mem::transmute(self.i2c.sr().read()) } } fn write_byte(&self, byte: u8) { @@ -120,7 +132,7 @@ impl, PINS> I2c { self.i2c.txr_rxr.read().data().bits() } - fn wait_for_interrupt(&self) -> Result<(), ErrorKind> { + fn wait_for_interrupt(&self) -> Result<(), Error> { loop { let sr = self.read_sr(); @@ -129,7 +141,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(ErrorKind::ArbitrationLoss); + return Err(Error::ArbitrationLost); } if sr.if_().bit_is_set() { @@ -141,11 +153,11 @@ impl, PINS> I2c { } } - fn wait_for_read(&self) -> Result<(), ErrorKind> { + fn wait_for_read(&self) -> Result<(), Error> { self.wait_for_interrupt() } - fn wait_for_write(&self) -> Result<(), ErrorKind> { + fn wait_for_write(&self) -> Result<(), Error> { self.wait_for_interrupt()?; if self.read_sr().rx_ack().bit_is_set() { @@ -153,7 +165,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown)); + return Err(Error::NoAck); } Ok(()) @@ -167,16 +179,14 @@ impl, PINS> I2c { const FLAG_READ: u8 = 1; const FLAG_WRITE: u8 = 0; -impl ErrorType for I2c { - type Error = ErrorKind; -} +impl, PINS> Read for I2c { + type Error = Error; -impl, PINS> i2c::I2c for I2c { fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); + return Err(Error::InvalidState); } // Write address + R @@ -202,12 +212,16 @@ impl, PINS> i2c::I2c for I2c } Ok(()) } +} + +impl, PINS> Write for I2c { + type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); + return Err(Error::InvalidState); } // Write address + W @@ -230,39 +244,10 @@ impl, PINS> i2c::I2c for I2c } Ok(()) } +} - fn write_iter>( - &mut self, - address: u8, - bytes: B, - ) -> Result<(), Self::Error> { - self.reset(); - - if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); - } - - // Write address + W - self.write_byte((address << 1) + FLAG_WRITE); - - // Generate start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - - // Write bytes - let mut bytes = bytes.into_iter().peekable(); - while let Some(byte) = bytes.next() { - self.write_byte(byte); - - if bytes.peek().is_some() { - self.write_cr(|w| w.wr().set_bit()); // all others - } else { - self.write_cr(|w| w.wr().set_bit().sto().set_bit()); // last one - } - self.wait_for_write()?; - } - Ok(()) - } +impl, PINS> WriteRead for I2c { + type Error = Error; fn write_read( &mut self, @@ -273,7 +258,7 @@ impl, PINS> i2c::I2c for I2c self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); + return Err(Error::InvalidState); } if !bytes.is_empty() && buffer.is_empty() { @@ -323,205 +308,4 @@ impl, PINS> i2c::I2c for I2c Ok(()) } } - - fn write_iter_read>( - &mut self, - address: u8, - bytes: B, - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.reset(); - - if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); - } - - let mut bytes = bytes.into_iter().peekable(); - if bytes.peek().is_some() && buffer.is_empty() { - self.write_iter(address, bytes) - } else if !buffer.is_empty() && bytes.peek().is_none() { - self.read(address, buffer) - } else if bytes.peek().is_none() && buffer.is_empty() { - Ok(()) - } else { - // Write address + W - self.write_byte((address << 1) + FLAG_WRITE); - - // Generate start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - - // Write bytes - for byte in bytes { - self.write_byte(byte); - - self.write_cr(|w| w.wr().set_bit()); - self.wait_for_write()?; - } - - // Write address + R - self.write_byte((address << 1) + FLAG_READ); - - // Generate repeated start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - - // Read bytes - let buffer_len = buffer.len(); - for (i, byte) in buffer.iter_mut().enumerate() { - if i != buffer_len - 1 { - // W + ACK - self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); - } else { - // W + NACK + STOP - self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); - } - self.wait_for_read()?; - - *byte = self.read_byte(); - } - - Ok(()) - } - } - - fn transaction<'a>( - &mut self, - address: u8, - operations: &mut [Operation<'a>], - ) -> Result<(), Self::Error> { - self.reset(); - - if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); - } - - let last_op = operations.len() - 1; - let mut last_flag = 0xFF; - for (i, op) in operations.iter_mut().enumerate() { - match op { - Operation::Read(bytes) => { - if last_flag != FLAG_READ { - // Write address + R - self.write_byte((address << 1) + FLAG_READ); - - // Generate repeated start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - last_flag = FLAG_READ; - } - - // Read bytes - let last_byte = bytes.len() - 1; - for (j, byte) in bytes.iter_mut().enumerate() { - if i != last_op || j != last_byte { - // W + ACK - self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); - } else { - // W + NACK + STOP - self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); - } - self.wait_for_read()?; - - *byte = self.read_byte(); - } - } - Operation::Write(bytes) => { - if last_flag != FLAG_WRITE { - // Write address + W - self.write_byte((address << 1) + FLAG_WRITE); - - // Generate start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - last_flag = FLAG_WRITE; - } - - // Write bytes - for (j, byte) in bytes.iter().enumerate() { - self.write_byte(*byte); - - if i != last_op || j != bytes.len() - 1 { - self.write_cr(|w| w.wr().set_bit()); - } else { - self.write_cr(|w| w.wr().set_bit().sto().set_bit()); - } - self.wait_for_write()?; - } - } - } - } - - Ok(()) - } - - fn transaction_iter<'a, O: IntoIterator>>( - &mut self, - address: u8, - operations: O, - ) -> Result<(), Self::Error> { - self.reset(); - - if self.read_sr().busy().bit_is_set() { - return Err(ErrorKind::Other); - } - - let mut last_flag = 0xFF; - let mut operations = operations.into_iter().peekable(); - while let Some(op) = operations.next() { - match op { - Operation::Read(bytes) => { - if last_flag != FLAG_READ { - // Write address + R - self.write_byte((address << 1) + FLAG_READ); - - // Generate repeated start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - last_flag = FLAG_READ; - } - - // Read bytes - let last_byte = bytes.len() - 1; - for (j, byte) in bytes.iter_mut().enumerate() { - if operations.peek().is_some() || j != last_byte { - // W + ACK - self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); - } else { - // W + NACK + STOP - self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); - } - self.wait_for_read()?; - - *byte = self.read_byte(); - } - } - Operation::Write(bytes) => { - if last_flag != FLAG_WRITE { - // Write address + W - self.write_byte((address << 1) + FLAG_WRITE); - - // Generate start condition and write command - self.write_cr(|w| w.sta().set_bit().wr().set_bit()); - self.wait_for_write()?; - last_flag = FLAG_WRITE; - } - - // Write bytes - for (j, byte) in bytes.iter().enumerate() { - self.write_byte(*byte); - - if operations.peek().is_some() || j != bytes.len() - 1 { - self.write_cr(|w| w.wr().set_bit()); - } else { - self.write_cr(|w| w.wr().set_bit().sto().set_bit()); - } - self.wait_for_write()?; - } - } - } - } - - Ok(()) - } } diff --git a/src/prelude.rs b/src/prelude.rs index a26b75f..c6ccd12 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,4 +7,9 @@ pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; -pub use embedded_hal::digital::blocking::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin; +pub use embedded_hal::digital::v2::{ + InputPin as _embedded_hal_digital_v2_InputPin, OutputPin as _embedded_hal_digital_v2_OutputPin, + StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, + ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, +}; +pub use embedded_hal::prelude::*; diff --git a/src/serial.rs b/src/serial.rs index c88c2ac..0184679 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -13,6 +13,7 @@ //! - RX: Pin 23 IOF0 //! - Interrupt::UART1 +use core::convert::Infallible; use core::ops::Deref; use embedded_hal::serial; @@ -113,12 +114,10 @@ impl Serial { } } -impl serial::ErrorType for Rx { - type Error = serial::ErrorKind; -} +impl serial::Read for Rx { + type Error = Infallible; -impl serial::nb::Read for Rx { - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { let rxdata = self.uart.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -129,12 +128,10 @@ impl serial::nb::Read for Rx { } } -impl serial::ErrorType for Tx { - type Error = serial::ErrorKind; -} +impl serial::Write for Tx { + type Error = Infallible; -impl serial::nb::Write for Tx { - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { let txdata = self.uart.txdata.read(); if txdata.full().bit_is_set() { @@ -147,7 +144,7 @@ impl serial::nb::Write for Tx { } } - fn flush(&mut self) -> nb::Result<(), Self::Error> { + fn flush(&mut self) -> nb::Result<(), Infallible> { if self.uart.ip.read().txwm().bit_is_set() { // FIFO count is below the receive watermark (1) Ok(()) diff --git a/src/spi.rs b/src/spi.rs index 5c447a2..d508849 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -24,7 +24,7 @@ //! - Interrupt::QSPI2 //! //! # Exclusive Bus usage example -//!```ignore +//!``` //! let pins = (mosi, miso, sck, cs0); //! let spi_bus = SpiBus::new(p.QSPI1, pins); //! @@ -35,7 +35,7 @@ //!``` //! //! # Shared Bus usage example -//!```ignore +//!``` //! let pins = (mosi, miso, sck); //! let spi_bus = SpiBus::shared(p.QSPI1, pins); //! diff --git a/src/spi/bus.rs b/src/spi/bus.rs index 921d74b..94ea72b 100644 --- a/src/spi/bus.rs +++ b/src/spi/bus.rs @@ -1,7 +1,7 @@ -use embedded_hal::spi::blocking::Operation; -pub use embedded_hal::spi::blocking::{Read, Transfer, TransferInplace, Write, WriteIter}; -pub use embedded_hal::spi::nb::FullDuplex; -pub use embedded_hal::spi::{ErrorKind, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use core::convert::Infallible; +use embedded_hal::blocking::spi::Operation; +pub use embedded_hal::blocking::spi::{Transfer, Write, WriteIter}; +pub use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use nb; @@ -103,7 +103,7 @@ where // ex-traits now only accessible via devices - pub(crate) fn read(&mut self) -> nb::Result { + pub(crate) fn read(&mut self) -> nb::Result { let rxdata = self.spi.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -113,7 +113,7 @@ where } } - pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), ErrorKind> { + pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { let txdata = self.spi.txdata.read(); if txdata.full().bit_is_set() { @@ -124,16 +124,16 @@ where } } - pub(crate) fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), ErrorKind> { + pub(crate) fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Infallible> { let mut iwrite = 0; let mut iread = 0; // Ensure that RX FIFO is empty self.wait_for_rxfifo(); - while iwrite < write.len() || iread < read.len() { - if iwrite < write.len() && self.spi.txdata.read().full().bit_is_clear() { - let byte = write.get(iwrite).unwrap_or(&0); + while iwrite < words.len() || iread < words.len() { + if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = unsafe { words.get_unchecked(iwrite) }; iwrite += 1; self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); } @@ -141,18 +141,16 @@ where if iread < iwrite { let data = self.spi.rxdata.read(); if data.empty().bit_is_clear() { - if let Some(d) = read.get_mut(iread) { - *d = data.data().bits() - }; + unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; iread += 1; } } } - Ok(()) + Ok(words) } - pub(crate) fn transfer_inplace(&mut self, words: &mut [u8]) -> Result<(), ErrorKind> { + pub(crate) fn write(&mut self, words: &[u8]) -> Result<(), Infallible> { let mut iwrite = 0; let mut iread = 0; @@ -167,9 +165,8 @@ where } if iread < iwrite { - let data = self.spi.rxdata.read(); - if data.empty().bit_is_clear() { - unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { iread += 1; } } @@ -178,7 +175,7 @@ where Ok(()) } - pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), ErrorKind> + pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), Infallible> where WI: IntoIterator, { @@ -214,20 +211,14 @@ where pub(crate) fn exec<'op>( &mut self, operations: &mut [Operation<'op, u8>], - ) -> Result<(), ErrorKind> { + ) -> Result<(), Infallible> { for op in operations { match op { - Operation::Read(words) => { - self.transfer(words, &[])?; + Operation::Transfer(words) => { + self.transfer(words)?; } Operation::Write(words) => { - self.transfer(&mut [], words)?; - } - Operation::Transfer(read_words, write_words) => { - self.transfer(read_words, write_words)?; - } - Operation::TransferInplace(words) => { - self.transfer_inplace(words)?; + self.write(words)?; } } } diff --git a/src/spi/exclusive_device.rs b/src/spi/exclusive_device.rs index 367ac15..d9e808e 100644 --- a/src/spi/exclusive_device.rs +++ b/src/spi/exclusive_device.rs @@ -1,7 +1,8 @@ -use embedded_hal::spi::{ - blocking::{Operation, Transactional, Transfer, TransferInplace, Write, WriteIter}, - nb::FullDuplex, - ErrorKind, ErrorType, +use core::convert::Infallible; + +use embedded_hal::{ + blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, + spi::FullDuplex, }; use crate::spi::SpiConfig; @@ -35,71 +36,61 @@ where } } -impl ErrorType for SpiExclusiveDevice { - type Error = ErrorKind; -} - -impl FullDuplex for SpiExclusiveDevice +impl FullDuplex for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - fn read(&mut self) -> nb::Result { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { self.bus.read() } - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { self.bus.send(byte) } } -impl Transfer for SpiExclusiveDevice +impl Transfer for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { - self.bus.start_frame(); - let result = self.bus.transfer(read, write); - self.bus.end_frame(); + type Error = Infallible; - result - } -} - -impl TransferInplace for SpiExclusiveDevice -where - SPI: SpiX, - PINS: Pins, -{ - fn transfer_inplace<'w>(&mut self, words: &'w mut [u8]) -> Result<(), Self::Error> { + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.bus.start_frame(); - let result = self.bus.transfer_inplace(words); + let result = self.bus.transfer(words); self.bus.end_frame(); result } } -impl Write for SpiExclusiveDevice +impl Write for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { + type Error = Infallible; + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { self.bus.start_frame(); - let result = self.bus.transfer(&mut [], words); + let result = self.bus.write(words); self.bus.end_frame(); result } } -impl WriteIter for SpiExclusiveDevice +impl WriteIter for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { + type Error = Infallible; + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, @@ -112,12 +103,14 @@ where } } -impl Transactional for SpiExclusiveDevice +impl Transactional for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Self::Error> { + type Error = Infallible; + + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { self.bus.start_frame(); let result = self.bus.exec(operations); self.bus.end_frame(); diff --git a/src/spi/shared_device.rs b/src/spi/shared_device.rs index bf6c53d..e611273 100644 --- a/src/spi/shared_device.rs +++ b/src/spi/shared_device.rs @@ -1,7 +1,8 @@ -use embedded_hal::spi::{ - blocking::{Operation, Transactional, Transfer, TransferInplace, Write, WriteIter}, - nb::FullDuplex, - ErrorKind, ErrorType, +use core::convert::Infallible; + +use embedded_hal::{ + blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, + spi::FullDuplex, }; use riscv::interrupt; @@ -39,17 +40,15 @@ where } } -impl ErrorType for SpiSharedDevice<'_, SPI, PINS, CS> { - type Error = ErrorKind; -} - -impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> +impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - fn read(&mut self) -> nb::Result { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); @@ -59,7 +58,7 @@ where }) } - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); @@ -70,41 +69,22 @@ where } } -impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> +impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { - interrupt::free(move |cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); - - bus.start_frame(); - let result = bus.transfer(read, write); - bus.end_frame(); - - result - }) - } -} + type Error = Infallible; -impl TransferInplace for SpiSharedDevice<'_, SPI, PINS, CS> -where - SPI: SpiX, - PINS: Pins, - CS: PinCS, -{ - fn transfer_inplace<'w>(&mut self, words: &'w mut [u8]) -> Result<(), Self::Error> { + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { interrupt::free(move |cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); bus.start_frame(); - let result = bus.transfer_inplace(words); + let result = bus.transfer(words); bus.end_frame(); result @@ -112,12 +92,14 @@ where } } -impl Write for SpiSharedDevice<'_, SPI, PINS, CS> +impl Write for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { + type Error = Infallible; + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); @@ -125,7 +107,7 @@ where bus.configure(&self.config, Some(CS::CS_INDEX)); bus.start_frame(); - let result = bus.transfer(&mut [], words); + let result = bus.write(words); bus.end_frame(); result @@ -133,12 +115,14 @@ where } } -impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> +impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { + type Error = Infallible; + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, @@ -157,13 +141,15 @@ where } } -impl Transactional for SpiSharedDevice<'_, SPI, PINS, CS> +impl Transactional for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, PINS: Pins, CS: PinCS, { - fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Self::Error> { + type Error = Infallible; + + fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); diff --git a/src/stdout.rs b/src/stdout.rs index 516a280..004bcc8 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -10,7 +10,7 @@ where impl<'p, T> Write for Stdout<'p, T> where - T: embedded_hal::serial::nb::Write, + T: embedded_hal::serial::Write, { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() { From d46c00c8f68b618ba0595abc647db1b60f90d39e Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 10 Jul 2022 11:27:46 -0700 Subject: [PATCH 268/315] update changelog from v0.9.4 side-branch release --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9966133..76d9f99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist +## [v0.9.4] - 2022-07-10 + +### Changed + +- Fixed code still using old `riscv::interrupt::Nr` + ## [v0.9.3] - 2021-08-15 ### Changed From ed6530c586c4f284e95f859d576779247dd9d4a4 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sun, 10 Jul 2022 11:35:37 -0700 Subject: [PATCH 269/315] bump MSRV to 1.59 due to riscv bump --- .github/workflows/ci.yaml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2addd1a..4366937 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.42.0 - rust: [nightly, stable, 1.42.0] + # All generated code should be running on stable now, MRSV is 1.59.0 + rust: [nightly, stable, 1.59.0] include: # Nightly is only for reference and allowed to fail diff --git a/README.md b/README.md index 81455da..bf2f875 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License From ba39078900ad7a2ab5d9a4b4c9af2e932f3fec54 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 11 Jul 2022 17:48:48 -0700 Subject: [PATCH 270/315] add rust-version requirement to Cargo.toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index e79aed9..f2079bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ description = "HAL for the E310x family of microcontrollers." keywords = ["riscv", "e310", "hal"] license = "ISC" edition = "2018" +rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } From 0d9473233d2effcb15df68f4e03f01253852b3cf Mon Sep 17 00:00:00 2001 From: Vadim Kaushan Date: Sun, 4 Sep 2022 08:22:24 +0300 Subject: [PATCH 271/315] Track changes in hifive1-link.x --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index e731326..ec4ac5f 100644 --- a/build.rs +++ b/build.rs @@ -43,6 +43,7 @@ fn main() { } fs::copy("hifive1-link.x", out_dir.join("hifive1-link.x")).unwrap(); + println!("cargo:rerun-if-changed=hifive1-link.x"); // Copy library with flash setup code let name = env::var("CARGO_PKG_NAME").unwrap(); From f17fb43d5317550b210606cf44d6cdd7b9e766df Mon Sep 17 00:00:00 2001 From: Timon Baetz Date: Thu, 29 Sep 2022 22:51:48 +0200 Subject: [PATCH 272/315] Add PWM driver --- CHANGELOG.md | 1 + src/lib.rs | 1 + src/pwm.rs | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 src/pwm.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d9f99..6762696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist +- Added Pulse Width Modulation interface implementing `embedded_hal::Pwm` ## [v0.9.4] - 2022-07-10 diff --git a/src/lib.rs b/src/lib.rs index 2141626..d543091 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ pub mod device; pub mod gpio; pub mod pmu; pub mod prelude; +pub mod pwm; pub mod rtc; pub mod serial; pub mod spi; diff --git a/src/pwm.rs b/src/pwm.rs new file mode 100644 index 0000000..7db8bf5 --- /dev/null +++ b/src/pwm.rs @@ -0,0 +1,235 @@ +//! # Pulse Width Modulation Interface +//! +//! You can use the `PWM` with these [Pwm] instances +//! +//! # PWM0 - 8 bit period and duty +//! - Channel 1: Pin 9 IOF1 +//! - Channel 2: Pin 10 IOF1 +//! - Channel 3: Pin 11 IOF1 +//! +//! # PWM1 - 16 bit period and duty +//! - Channel 1: Pin 3 IOF1 +//! - Channel 2: Pin 5 IOF1 +//! - Channel 3: Pin 6 IOF1 +//! +//! # PWM2 - 16 bit period and duty +//! - Channel 1: Pin 17 IOF1 +//! - Channel 2: Pin 18 IOF1 +//! - Channel 3: Pin 19 IOF1 + +use core::marker::PhantomData; +use core::ops::Deref; + +use e310x::{pwm0, PWM0, PWM1, PWM2}; + +/// PWM comparator index +#[derive(Copy, Clone)] +pub enum CmpIndex { + /// PWM comparator 1 + Cmp1, + /// PWM comparator 1 + Cmp2, + /// PWM comparator 1 + Cmp3, +} + +/// PWM pin - DO NOT IMPLEMENT THIS TRAIT +pub trait Pin { + #[doc(hidden)] + const CMP_INDEX: CmpIndex; +} + +mod pwm0_impl { + use super::{CmpIndex, Pin, PWM0}; + use crate::gpio::{gpio0, NoInvert, IOF1}; + + impl Pin for gpio0::Pin1> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; + } + + impl Pin for gpio0::Pin2> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; + } + + impl Pin for gpio0::Pin3> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; + } +} + +mod pwm1_impl { + use super::{CmpIndex, Pin, PWM1}; + use crate::gpio::{gpio0, NoInvert, IOF1}; + + impl Pin for gpio0::Pin19> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; + } + + impl Pin for gpio0::Pin21> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; + } + + impl Pin for gpio0::Pin22> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; + } +} + +mod pwm2_impl { + use super::{CmpIndex, Pin, PWM2}; + use crate::gpio::{gpio0, NoInvert, IOF1}; + + impl Pin for gpio0::Pin11> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; + } + + impl Pin for gpio0::Pin12> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; + } + + impl Pin for gpio0::Pin13> { + const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; + } +} + +/// PWM channel +pub struct Channel { + _pwm: PhantomData, + cmp_index: CmpIndex, +} + +impl Channel { + /// Constructs a PWM channel from a PWM pin for use with [Pwm] + pub fn from(_: PIN) -> Channel + where + PIN: Pin, + { + Channel { + _pwm: PhantomData, + cmp_index: PIN::CMP_INDEX, + } + } +} + +impl Clone for Channel { + fn clone(&self) -> Self { + Self { + _pwm: self._pwm.clone(), + cmp_index: self.cmp_index.clone(), + } + } +} + +impl Copy for Channel {} + +#[doc(hidden)] +pub trait PwmX: Deref { + type CmpWidth: Ord; + fn bits_from_cmp_width(other: Self::CmpWidth) -> u32; + fn bits_into_cmp_width(other: u32) -> Self::CmpWidth; +} + +macro_rules! pwmx_impl { + ($PWM:ident,$CMP_WIDTH:ident) => { + impl PwmX for $PWM { + type CmpWidth = $CMP_WIDTH; + fn bits_from_cmp_width(other: Self::CmpWidth) -> u32 { + other as u32 + } + fn bits_into_cmp_width(other: u32) -> Self::CmpWidth { + other as Self::CmpWidth + } + } + }; +} + +pwmx_impl!(PWM0, u8); +pwmx_impl!(PWM1, u16); +pwmx_impl!(PWM2, u16); + +/// PWM abstraction +/// +/// # Notes +/// +/// [PWM0] has a max period of 255, as it only has an 8 bit comparison register, +/// the rest of them have a max value of 2^16 as they have 16 bit registers. +pub struct Pwm { + pwm: PWM, +} + +impl Pwm { + /// Configures a PWM device + pub fn new(pwm: PWM) -> Self { + pwm.cfg.reset(); + pwm.cfg.write(|w| { + w.zerocmp() + .set_bit() + .enalways() + .set_bit() + .deglitch() + .set_bit() + }); + pwm.cmp0.reset(); + pwm.cmp1.reset(); + pwm.cmp2.reset(); + pwm.cmp3.reset(); + Self { pwm } + } +} + +impl embedded_hal::Pwm for Pwm { + type Channel = Channel; + + type Time = PWM::CmpWidth; + + type Duty = PWM::CmpWidth; + + fn enable(&mut self, channel: Self::Channel) { + match channel.cmp_index { + CmpIndex::Cmp1 => self.pwm.cmp1.write(|w| unsafe { w.bits(u32::MAX) }), + CmpIndex::Cmp2 => self.pwm.cmp2.write(|w| unsafe { w.bits(u32::MAX) }), + CmpIndex::Cmp3 => self.pwm.cmp3.write(|w| unsafe { w.bits(u32::MAX) }), + } + } + + fn disable(&mut self, channel: Self::Channel) { + match channel.cmp_index { + CmpIndex::Cmp1 => self.pwm.cmp1.reset(), + CmpIndex::Cmp2 => self.pwm.cmp2.reset(), + CmpIndex::Cmp3 => self.pwm.cmp3.reset(), + } + } + + fn get_period(&self) -> Self::Time { + PWM::bits_into_cmp_width(self.pwm.cmp0.read().bits()) + } + + fn get_duty(&self, channel: Self::Channel) -> Self::Duty { + let duty = match channel.cmp_index { + CmpIndex::Cmp1 => self.pwm.cmp1.read().bits(), + CmpIndex::Cmp2 => self.pwm.cmp2.read().bits(), + CmpIndex::Cmp3 => self.pwm.cmp3.read().bits(), + }; + PWM::bits_into_cmp_width(duty) + } + + fn get_max_duty(&self) -> Self::Duty { + self.get_period() + } + + fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { + let duty = PWM::bits_from_cmp_width(duty.min(self.get_max_duty())); + match channel.cmp_index { + CmpIndex::Cmp1 => self.pwm.cmp1.write(|w| unsafe { w.bits(duty) }), + CmpIndex::Cmp2 => self.pwm.cmp2.write(|w| unsafe { w.bits(duty) }), + CmpIndex::Cmp3 => self.pwm.cmp3.write(|w| unsafe { w.bits(duty) }), + } + } + + fn set_period

(&mut self, period: P) + where + P: Into, + { + let period = PWM::bits_from_cmp_width(period.into()); + self.pwm.count.reset(); + self.pwm.cmp0.write(|w| unsafe { w.bits(period) }); + } +} From e7c4bf17c3a65e63978da11d2bfe1a12163786bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 17 Oct 2022 16:29:39 +0200 Subject: [PATCH 273/315] Replaced board-specific LED impls with a macro --- src/led.rs | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/led.rs b/src/led.rs index d2c1b27..c860a94 100644 --- a/src/led.rs +++ b/src/led.rs @@ -13,7 +13,7 @@ use e310x_hal::gpio::gpio0::Pin5; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22}; use e310x_hal::gpio::{Invert, Output, Regular}; -use embedded_hal::digital::v2::OutputPin; +use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] /// Red LED @@ -47,36 +47,34 @@ pub trait Led { /// Turns the LED on fn on(&mut self); -} - -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] -impl Led for RED { - fn off(&mut self) { - self.set_low().unwrap(); - } - fn on(&mut self) { - self.set_high().unwrap(); - } + /// Toggles the LED state + fn toggle(&mut self); } -#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] -impl Led for GREEN { - fn off(&mut self) { - self.set_low().unwrap(); - } +/// Macro to implement the Led trait for each of the board LEDs +macro_rules! led_impl { + ($($LEDTYPE:ident),+) => { + $( + impl Led for $LEDTYPE { + fn off(&mut self) { + self.set_low().unwrap(); + } + + fn on(&mut self) { + self.set_high().unwrap(); + } - fn on(&mut self) { - self.set_high().unwrap(); + fn toggle(&mut self) { + ToggleableOutputPin::toggle(self).unwrap(); + } + } + )+ } } -impl Led for BLUE { - fn off(&mut self) { - self.set_low().unwrap(); - } +/// Call the macro for each LED +#[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] +led_impl!(RED, GREEN); - fn on(&mut self) { - self.set_high().unwrap(); - } -} +led_impl!(BLUE); \ No newline at end of file From f656193a3ca80400c1ec8502f9fcd97ffdffed6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 17 Oct 2022 23:32:03 +0200 Subject: [PATCH 274/315] Cargo fmt --- src/led.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/led.rs b/src/led.rs index c860a94..5530d19 100644 --- a/src/led.rs +++ b/src/led.rs @@ -57,18 +57,18 @@ macro_rules! led_impl { ($($LEDTYPE:ident),+) => { $( impl Led for $LEDTYPE { - fn off(&mut self) { - self.set_low().unwrap(); - } + fn off(&mut self) { + self.set_low().unwrap(); + } - fn on(&mut self) { - self.set_high().unwrap(); - } + fn on(&mut self) { + self.set_high().unwrap(); + } - fn toggle(&mut self) { - ToggleableOutputPin::toggle(self).unwrap(); + fn toggle(&mut self) { + ToggleableOutputPin::toggle(self).unwrap(); + } } - } )+ } } @@ -77,4 +77,4 @@ macro_rules! led_impl { #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] led_impl!(RED, GREEN); -led_impl!(BLUE); \ No newline at end of file +led_impl!(BLUE); From a3c0965b348aed77d2a1182ec68fc0039e1ba4f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Mon, 17 Oct 2022 23:33:35 +0200 Subject: [PATCH 275/315] Cargo clippy --- src/stdout.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stdout.rs b/src/stdout.rs index e683f36..68779d4 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -19,8 +19,8 @@ struct SerialWrapper(Tx); impl core::fmt::Write for SerialWrapper { fn write_str(&mut self, s: &str) -> fmt::Result { for byte in s.as_bytes() { - if *byte == '\n' as u8 { - let res = block!(self.0.write('\r' as u8)); + if *byte == b'\n' { + let res = block!(self.0.write(b'\r')); if res.is_err() { return Err(::core::fmt::Error); @@ -53,7 +53,7 @@ pub fn configure( interrupt::free(|_| unsafe { STDOUT.replace(SerialWrapper(tx)); }); - return rx; + rx } /// Writes string to stdout From 7c510f6888eb506d476ae7b164b2a474ef21ac22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Wed, 30 Nov 2022 17:36:49 +0100 Subject: [PATCH 276/315] Create optional external interupt handler --- Cargo.toml | 3 ++- build.rs | 14 ++++++++++++++ interrupts.x | 3 +++ src/exthandler.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 build.rs create mode 100644 interrupts.x create mode 100644 src/exthandler.rs diff --git a/Cargo.toml b/Cargo.toml index f2079bb..bba03b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,11 @@ rust-version = "1.59" embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" -e310x = { version = "0.9.0", features = ["rt"] } +e310x = { path = "../e310x", features = ["rt"] } [features] g002 = ["e310x/g002"] +virq = [] [package.metadata.docs.rs] features = ["g002"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..c694369 --- /dev/null +++ b/build.rs @@ -0,0 +1,14 @@ +use std::io::Write; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() { + // Put the linker script somewhere the linker can find it + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + println!("cargo:rustc-link-search={}", out_dir.display()); + fs::File::create(out_dir.join("interrupts.x")) + .unwrap() + .write_all(include_bytes!("interrupts.x")) + .unwrap(); + println!("cargo:rerun-if-changed=interrupts.x"); +} diff --git a/interrupts.x b/interrupts.x new file mode 100644 index 0000000..f831b37 --- /dev/null +++ b/interrupts.x @@ -0,0 +1,3 @@ +EXTERN(HANDLERS); +EXTERN(DefaultMachineExternal); +PROVIDE(GPIO4 = DefaultMachineExternal); diff --git a/src/exthandler.rs b/src/exthandler.rs new file mode 100644 index 0000000..700ddd8 --- /dev/null +++ b/src/exthandler.rs @@ -0,0 +1,39 @@ +//! Optional external interrupt handler +use crate::core::CorePeripherals; + +/* Empty definition of all external handler functions */ +extern "C" { + /// w + fn GPIO4(); +} + +#[no_mangle] +/// Array of handlers +pub static HANDLERS : [unsafe extern "C" fn (); 1] = [ + GPIO4 +]; + +#[no_mangle] +/// Default external handler +pub fn DefaultMachineExternal () { + loop { + continue; + } +} +/// Optional handler to use for external interrupts. +/// It will automatically claim any interrupt and call the appropriate +/// handler function (ex.: GPIO0() for GPIO0 interrupts). +/// The handler functions can be overriden by the user, otherwise default +/// behavior will be called. +#[no_mangle] +//#[feature(virq)] +unsafe fn MachineExternal() { + let mut plic = CorePeripherals::steal().plic; + let interrupt = plic.claim.claim().unwrap(); + /* Match the appropriate external interrupt */ + match interrupt { + e310x::Interrupt::GPIO4 => { HANDLERS[0]() }, + _ => {} + } + plic.claim.complete(interrupt); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d543091..dc61404 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub mod spi; pub mod stdout; pub mod time; pub mod wdog; +pub mod exthandler; #[cfg(feature = "g002")] pub mod i2c; From f333eb23d558def0a4a54d00798da214145421fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Thu, 1 Dec 2022 09:59:18 +0100 Subject: [PATCH 277/315] Format code with rustfmt --- src/exthandler.rs | 10 ++++------ src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/exthandler.rs b/src/exthandler.rs index 700ddd8..1738c8b 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -9,13 +9,11 @@ extern "C" { #[no_mangle] /// Array of handlers -pub static HANDLERS : [unsafe extern "C" fn (); 1] = [ - GPIO4 -]; +pub static HANDLERS: [unsafe extern "C" fn(); 1] = [GPIO4]; #[no_mangle] /// Default external handler -pub fn DefaultMachineExternal () { +pub fn DefaultMachineExternal() { loop { continue; } @@ -32,8 +30,8 @@ unsafe fn MachineExternal() { let interrupt = plic.claim.claim().unwrap(); /* Match the appropriate external interrupt */ match interrupt { - e310x::Interrupt::GPIO4 => { HANDLERS[0]() }, + e310x::Interrupt::GPIO4 => HANDLERS[0](), _ => {} } plic.claim.complete(interrupt); -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index dc61404..4a446bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod clock; pub mod core; pub mod delay; pub mod device; +pub mod exthandler; pub mod gpio; pub mod pmu; pub mod prelude; @@ -22,7 +23,6 @@ pub mod spi; pub mod stdout; pub mod time; pub mod wdog; -pub mod exthandler; #[cfg(feature = "g002")] pub mod i2c; From c17e6d661780fd674d675795ebb839a94f857b66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Thu, 1 Dec 2022 12:34:12 +0100 Subject: [PATCH 278/315] Create all handlers and simplify interrupt matching --- Cargo.toml | 2 +- src/exthandler.rs | 121 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bba03b6..6d3cc01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.59" embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" -e310x = { path = "../e310x", features = ["rt"] } +e310x = { version = "0.10.0", features = ["rt"] } [features] g002 = ["e310x/g002"] diff --git a/src/exthandler.rs b/src/exthandler.rs index 1738c8b..7e45d2e 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -1,20 +1,126 @@ //! Optional external interrupt handler use crate::core::CorePeripherals; -/* Empty definition of all external handler functions */ +/* Empty definition of all external handler functions, to be provided + in the .x file and declared by the user */ extern "C" { - /// w + fn WATCHDOG(); + fn RTC(); + fn UART0(); + fn UART1(); + fn QSPI0(); + fn QSPI1(); + fn QSPI2(); + fn GPIO0(); + fn GPIO1(); + fn GPIO2(); + fn GPIO3(); fn GPIO4(); + fn GPIO5(); + fn GPIO6(); + fn GPIO7(); + fn GPIO8(); + fn GPIO9(); + fn GPIO10(); + fn GPIO11(); + fn GPIO12(); + fn GPIO13(); + fn GPIO14(); + fn GPIO15(); + fn GPIO16(); + fn GPIO17(); + fn GPIO18(); + fn GPIO19(); + fn GPIO20(); + fn GPIO21(); + fn GPIO22(); + fn GPIO23(); + fn GPIO24(); + fn GPIO25(); + fn GPIO26(); + fn GPIO27(); + fn GPIO28(); + fn GPIO29(); + fn GPIO30(); + fn GPIO31(); + fn PWM0CMP0(); + fn PWM0CMP1(); + fn PWM0CMP2(); + fn PWM0CMP3(); + fn PWM1CMP0(); + fn PWM1CMP1(); + fn PWM1CMP2(); + fn PWM1CMP3(); + fn PWM2CMP0(); + fn PWM2CMP1(); + fn PWM2CMP2(); + fn PWM2CMP3(); + fn I2C0(); } #[no_mangle] /// Array of handlers -pub static HANDLERS: [unsafe extern "C" fn(); 1] = [GPIO4]; +pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ + WATCHDOG, + RTC, + UART0, + UART1, + QSPI0, + QSPI1, + QSPI2, + GPIO0, + GPIO1, + GPIO2, + GPIO3, + GPIO4, + GPIO5, + GPIO6, + GPIO7, + GPIO8, + GPIO9, + GPIO10, + GPIO11, + GPIO12, + GPIO13, + GPIO14, + GPIO15, + GPIO16, + GPIO17, + GPIO18, + GPIO19, + GPIO20, + GPIO21, + GPIO22, + GPIO23, + GPIO24, + GPIO25, + GPIO26, + GPIO27, + GPIO28, + GPIO29, + GPIO30, + GPIO31, + PWM0CMP0, + PWM0CMP1, + PWM0CMP2, + PWM0CMP3, + PWM1CMP0, + PWM1CMP1, + PWM1CMP2, + PWM1CMP3, + PWM2CMP0, + PWM2CMP1, + PWM2CMP2, + PWM2CMP3, + I2C0, +]; #[no_mangle] /// Default external handler pub fn DefaultMachineExternal() { loop { + /* do nothing, but we need a side effect so LLVM does not optimize + this */ continue; } } @@ -26,12 +132,15 @@ pub fn DefaultMachineExternal() { #[no_mangle] //#[feature(virq)] unsafe fn MachineExternal() { + /* Steal the PLIC peripheral to claim the interrupt */ let mut plic = CorePeripherals::steal().plic; let interrupt = plic.claim.claim().unwrap(); /* Match the appropriate external interrupt */ - match interrupt { - e310x::Interrupt::GPIO4 => HANDLERS[0](), - _ => {} + /* Interrupt 0 is defined as no interrupt, so we treat it independently */ + if interrupt as u16 == 0 { DefaultMachineExternal() } + else { + // Offset the handlers as we do not work with interrupt = 0 + HANDLERS[(interrupt as usize) - 1](); } plic.claim.complete(interrupt); } From a514a13bdfd524eff678a082267115b37485ff74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Fri, 2 Dec 2022 14:01:51 +0100 Subject: [PATCH 279/315] Comment the linker script and include other .x --- build.rs | 5 +---- interrupts.x | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index c694369..77c4e79 100644 --- a/build.rs +++ b/build.rs @@ -6,9 +6,6 @@ fn main() { // Put the linker script somewhere the linker can find it let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out_dir.display()); - fs::File::create(out_dir.join("interrupts.x")) - .unwrap() - .write_all(include_bytes!("interrupts.x")) - .unwrap(); + fs::copy("interrupts.x", out_dir.join("interrupts.x")).unwrap(); println!("cargo:rerun-if-changed=interrupts.x"); } diff --git a/interrupts.x b/interrupts.x index f831b37..0158cb9 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,3 +1,8 @@ +/* We have to include previous .x files and their dependencies */ +INCLUDE hifive1-link.x + +/* Declare the external handlers array and the default handler as external symbols */ EXTERN(HANDLERS); EXTERN(DefaultMachineExternal); +/* Provide the weak symbols for each interrupt handler */ PROVIDE(GPIO4 = DefaultMachineExternal); From 8a7d043a6cca470e50022a71c1bb724ffdfd1b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Fri, 2 Dec 2022 14:11:26 +0100 Subject: [PATCH 280/315] * interrupts.x: Add handlers for each interrupt source --- interrupts.x | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/interrupts.x b/interrupts.x index 0158cb9..dc271cf 100644 --- a/interrupts.x +++ b/interrupts.x @@ -5,4 +5,55 @@ INCLUDE hifive1-link.x EXTERN(HANDLERS); EXTERN(DefaultMachineExternal); /* Provide the weak symbols for each interrupt handler */ +PROVIDE(WATCHDOG = DefaultMachineExternal); +PROVIDE(RTC = DefaultMachineExternal); +PROVIDE(UART0 = DefaultMachineExternal); +PROVIDE(UART1 = DefaultMachineExternal); +PROVIDE(QSPI0 = DefaultMachineExternal); +PROVIDE(QSPI1 = DefaultMachineExternal); +PROVIDE(QSPI2 = DefaultMachineExternal); +PROVIDE(GPIO0 = DefaultMachineExternal); +PROVIDE(GPIO1 = DefaultMachineExternal); +PROVIDE(GPIO2 = DefaultMachineExternal); +PROVIDE(GPIO3 = DefaultMachineExternal); PROVIDE(GPIO4 = DefaultMachineExternal); +PROVIDE(GPIO5 = DefaultMachineExternal); +PROVIDE(GPIO6 = DefaultMachineExternal); +PROVIDE(GPIO7 = DefaultMachineExternal); +PROVIDE(GPIO8 = DefaultMachineExternal); +PROVIDE(GPIO9 = DefaultMachineExternal); +PROVIDE(GPIO10 = DefaultMachineExternal); +PROVIDE(GPIO11 = DefaultMachineExternal); +PROVIDE(GPIO12 = DefaultMachineExternal); +PROVIDE(GPIO13 = DefaultMachineExternal); +PROVIDE(GPIO14 = DefaultMachineExternal); +PROVIDE(GPIO15 = DefaultMachineExternal); +PROVIDE(GPIO16 = DefaultMachineExternal); +PROVIDE(GPIO17 = DefaultMachineExternal); +PROVIDE(GPIO18 = DefaultMachineExternal); +PROVIDE(GPIO19 = DefaultMachineExternal); +PROVIDE(GPIO20 = DefaultMachineExternal); +PROVIDE(GPIO21 = DefaultMachineExternal); +PROVIDE(GPIO22 = DefaultMachineExternal); +PROVIDE(GPIO23 = DefaultMachineExternal); +PROVIDE(GPIO24 = DefaultMachineExternal); +PROVIDE(GPIO25 = DefaultMachineExternal); +PROVIDE(GPIO26 = DefaultMachineExternal); +PROVIDE(GPIO27 = DefaultMachineExternal); +PROVIDE(GPIO28 = DefaultMachineExternal); +PROVIDE(GPIO29 = DefaultMachineExternal); +PROVIDE(GPIO30 = DefaultMachineExternal); +PROVIDE(GPIO31 = DefaultMachineExternal); +PROVIDE(PWM0CMP0 = DefaultMachineExternal); +PROVIDE(PWM0CMP1 = DefaultMachineExternal); +PROVIDE(PWM0CMP2 = DefaultMachineExternal); +PROVIDE(PWM0CMP3 = DefaultMachineExternal); +PROVIDE(PWM1CMP0 = DefaultMachineExternal); +PROVIDE(PWM1CMP1 = DefaultMachineExternal); +PROVIDE(PWM1CMP2 = DefaultMachineExternal); +PROVIDE(PWM1CMP3 = DefaultMachineExternal); +PROVIDE(PWM2CMP0 = DefaultMachineExternal); +PROVIDE(PWM2CMP1 = DefaultMachineExternal); +PROVIDE(PWM2CMP2 = DefaultMachineExternal); +PROVIDE(PWM2CMP3 = DefaultMachineExternal); +PROVIDE(I2C0 = DefaultMachineExternal); From 0bd4329f8bd44f60bc4d6272852dedefd7820ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Wed, 7 Dec 2022 14:18:10 +0100 Subject: [PATCH 281/315] Add feature for exthandler and linker flag --- .cargo/config.toml | 2 ++ Cargo.toml | 2 +- interrupts.x | 3 --- src/exthandler.rs | 14 ++++++++++---- 4 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..3ae2c96 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = [ "-C", "link-arg=-Tinterrupts.x"] \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 6d3cc01..08f1d99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.59" embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" -e310x = { version = "0.10.0", features = ["rt"] } +e310x = { version = "0.9.0", features = ["rt"] } [features] g002 = ["e310x/g002"] diff --git a/interrupts.x b/interrupts.x index dc271cf..db838c9 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,6 +1,3 @@ -/* We have to include previous .x files and their dependencies */ -INCLUDE hifive1-link.x - /* Declare the external handlers array and the default handler as external symbols */ EXTERN(HANDLERS); EXTERN(DefaultMachineExternal); diff --git a/src/exthandler.rs b/src/exthandler.rs index 7e45d2e..6fe5a2f 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -1,8 +1,9 @@ //! Optional external interrupt handler use crate::core::CorePeripherals; -/* Empty definition of all external handler functions, to be provided - in the .x file and declared by the user */ +/* Empty definition of all external handler functions, provided + in interrupts.x. Can be overwritten by the user. */ +#[cfg(feature="virq")] extern "C" { fn WATCHDOG(); fn RTC(); @@ -59,6 +60,7 @@ extern "C" { } #[no_mangle] +#[cfg(feature="virq")] /// Array of handlers pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ WATCHDOG, @@ -116,6 +118,7 @@ pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ ]; #[no_mangle] +#[cfg(feature="virq")] /// Default external handler pub fn DefaultMachineExternal() { loop { @@ -130,7 +133,7 @@ pub fn DefaultMachineExternal() { /// The handler functions can be overriden by the user, otherwise default /// behavior will be called. #[no_mangle] -//#[feature(virq)] +#[cfg(feature="virq")] unsafe fn MachineExternal() { /* Steal the PLIC peripheral to claim the interrupt */ let mut plic = CorePeripherals::steal().plic; @@ -138,9 +141,12 @@ unsafe fn MachineExternal() { /* Match the appropriate external interrupt */ /* Interrupt 0 is defined as no interrupt, so we treat it independently */ if interrupt as u16 == 0 { DefaultMachineExternal() } - else { + else if interrupt < HANDLERS.len() && interrupt > 0 { // Offset the handlers as we do not work with interrupt = 0 HANDLERS[(interrupt as usize) - 1](); + } else { + return; } + // Claim PLIC interrupt source as complete by this handler plic.claim.complete(interrupt); } From 70b74192a197b317787a5b68da41f1db58b52f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Wed, 7 Dec 2022 14:22:14 +0100 Subject: [PATCH 282/315] Cargo fmt --- src/exthandler.rs | 72 +++++++++-------------------------------------- 1 file changed, 13 insertions(+), 59 deletions(-) diff --git a/src/exthandler.rs b/src/exthandler.rs index 6fe5a2f..05f48af 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -2,8 +2,8 @@ use crate::core::CorePeripherals; /* Empty definition of all external handler functions, provided - in interrupts.x. Can be overwritten by the user. */ -#[cfg(feature="virq")] +in interrupts.x. Can be overwritten by the user. */ +#[cfg(feature = "virq")] extern "C" { fn WATCHDOG(); fn RTC(); @@ -60,65 +60,18 @@ extern "C" { } #[no_mangle] -#[cfg(feature="virq")] +#[cfg(feature = "virq")] /// Array of handlers pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ - WATCHDOG, - RTC, - UART0, - UART1, - QSPI0, - QSPI1, - QSPI2, - GPIO0, - GPIO1, - GPIO2, - GPIO3, - GPIO4, - GPIO5, - GPIO6, - GPIO7, - GPIO8, - GPIO9, - GPIO10, - GPIO11, - GPIO12, - GPIO13, - GPIO14, - GPIO15, - GPIO16, - GPIO17, - GPIO18, - GPIO19, - GPIO20, - GPIO21, - GPIO22, - GPIO23, - GPIO24, - GPIO25, - GPIO26, - GPIO27, - GPIO28, - GPIO29, - GPIO30, - GPIO31, - PWM0CMP0, - PWM0CMP1, - PWM0CMP2, - PWM0CMP3, - PWM1CMP0, - PWM1CMP1, - PWM1CMP2, - PWM1CMP3, - PWM2CMP0, - PWM2CMP1, - PWM2CMP2, - PWM2CMP3, - I2C0, + WATCHDOG, RTC, UART0, UART1, QSPI0, QSPI1, QSPI2, GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, + GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13, GPIO14, GPIO15, GPIO16, GPIO17, + GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, GPIO24, GPIO25, GPIO26, GPIO27, GPIO28, GPIO29, + GPIO30, GPIO31, PWM0CMP0, PWM0CMP1, PWM0CMP2, PWM0CMP3, PWM1CMP0, PWM1CMP1, PWM1CMP2, PWM1CMP3, + PWM2CMP0, PWM2CMP1, PWM2CMP2, PWM2CMP3, I2C0, ]; #[no_mangle] -#[cfg(feature="virq")] +#[cfg(feature = "virq")] /// Default external handler pub fn DefaultMachineExternal() { loop { @@ -133,15 +86,16 @@ pub fn DefaultMachineExternal() { /// The handler functions can be overriden by the user, otherwise default /// behavior will be called. #[no_mangle] -#[cfg(feature="virq")] +#[cfg(feature = "virq")] unsafe fn MachineExternal() { /* Steal the PLIC peripheral to claim the interrupt */ let mut plic = CorePeripherals::steal().plic; let interrupt = plic.claim.claim().unwrap(); /* Match the appropriate external interrupt */ /* Interrupt 0 is defined as no interrupt, so we treat it independently */ - if interrupt as u16 == 0 { DefaultMachineExternal() } - else if interrupt < HANDLERS.len() && interrupt > 0 { + if interrupt as u16 == 0 { + DefaultMachineExternal() + } else if interrupt < HANDLERS.len() && interrupt > 0 { // Offset the handlers as we do not work with interrupt = 0 HANDLERS[(interrupt as usize) - 1](); } else { From 8f9232648c2ea616841336170b102cea5e87902a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Wed, 7 Dec 2022 14:23:33 +0100 Subject: [PATCH 283/315] Remove unused import --- src/exthandler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exthandler.rs b/src/exthandler.rs index 05f48af..8d51efb 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -1,5 +1,4 @@ //! Optional external interrupt handler -use crate::core::CorePeripherals; /* Empty definition of all external handler functions, provided in interrupts.x. Can be overwritten by the user. */ From 1469acac20a8fff92f0020092956f5b1b6694839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 16:38:53 +0100 Subject: [PATCH 284/315] Leverage the virq feature script to hifive1 --- .cargo/config.toml | 2 -- Cargo.toml | 2 +- build.rs | 1 - interrupts.x | 4 ++-- src/exthandler.rs | 12 ++++++------ src/lib.rs | 1 + 6 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 3ae2c96..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -rustflags = [ "-C", "link-arg=-Tinterrupts.x"] \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 08f1d99..bba03b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.59" embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" -e310x = { version = "0.9.0", features = ["rt"] } +e310x = { path = "../e310x", features = ["rt"] } [features] g002 = ["e310x/g002"] diff --git a/build.rs b/build.rs index 77c4e79..35e87fd 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,3 @@ -use std::io::Write; use std::path::PathBuf; use std::{env, fs}; diff --git a/interrupts.x b/interrupts.x index db838c9..9e28ce7 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,6 +1,6 @@ /* Declare the external handlers array and the default handler as external symbols */ -EXTERN(HANDLERS); -EXTERN(DefaultMachineExternal); +// EXTERN(HANDLERS); +// EXTERN(DefaultMachineExternal); /* Provide the weak symbols for each interrupt handler */ PROVIDE(WATCHDOG = DefaultMachineExternal); PROVIDE(RTC = DefaultMachineExternal); diff --git a/src/exthandler.rs b/src/exthandler.rs index 8d51efb..210b156 100644 --- a/src/exthandler.rs +++ b/src/exthandler.rs @@ -1,8 +1,9 @@ //! Optional external interrupt handler +#[allow(unused)] +use crate::core::CorePeripherals; /* Empty definition of all external handler functions, provided in interrupts.x. Can be overwritten by the user. */ -#[cfg(feature = "virq")] extern "C" { fn WATCHDOG(); fn RTC(); @@ -59,7 +60,6 @@ extern "C" { } #[no_mangle] -#[cfg(feature = "virq")] /// Array of handlers pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ WATCHDOG, RTC, UART0, UART1, QSPI0, QSPI1, QSPI2, GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, @@ -70,7 +70,7 @@ pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ ]; #[no_mangle] -#[cfg(feature = "virq")] +#[allow(non_snake_case)] /// Default external handler pub fn DefaultMachineExternal() { loop { @@ -85,16 +85,16 @@ pub fn DefaultMachineExternal() { /// The handler functions can be overriden by the user, otherwise default /// behavior will be called. #[no_mangle] -#[cfg(feature = "virq")] +#[allow(non_snake_case)] unsafe fn MachineExternal() { /* Steal the PLIC peripheral to claim the interrupt */ let mut plic = CorePeripherals::steal().plic; let interrupt = plic.claim.claim().unwrap(); /* Match the appropriate external interrupt */ /* Interrupt 0 is defined as no interrupt, so we treat it independently */ - if interrupt as u16 == 0 { + if interrupt as usize == 0 { DefaultMachineExternal() - } else if interrupt < HANDLERS.len() && interrupt > 0 { + } else if (interrupt as usize) < HANDLERS.len() && (interrupt as usize > 0) { // Offset the handlers as we do not work with interrupt = 0 HANDLERS[(interrupt as usize) - 1](); } else { diff --git a/src/lib.rs b/src/lib.rs index 4a446bd..445054b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod clock; pub mod core; pub mod delay; pub mod device; +#[cfg(feature = "virq")] pub mod exthandler; pub mod gpio; pub mod pmu; From 33da6acf1c03e59ea161e9fba61091de5ea14a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 16:42:31 +0100 Subject: [PATCH 285/315] Bump version --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bba03b6..83e37b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.3" +version = "0.10.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -14,7 +14,7 @@ rust-version = "1.59" embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = "0.7.0" -e310x = { path = "../e310x", features = ["rt"] } +e310x = { version = "0.10.0", features = ["rt"] } [features] g002 = ["e310x/g002"] From f62acf3a0ad5eefb647cb400dcf0fda37f4a587c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 16:49:28 +0100 Subject: [PATCH 286/315] test (rebase later) --- build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 35e87fd..8ff787c 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +/* use std::path::PathBuf; use std::{env, fs}; fn main() { @@ -8,3 +8,4 @@ fn main() { fs::copy("interrupts.x", out_dir.join("interrupts.x")).unwrap(); println!("cargo:rerun-if-changed=interrupts.x"); } + */ \ No newline at end of file From 8d179504003d3e78210151054f0faee5d69f5388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 16:54:11 +0100 Subject: [PATCH 287/315] Test without build.rs --- build.rs => UNUSED.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build.rs => UNUSED.rs (100%) diff --git a/build.rs b/UNUSED.rs similarity index 100% rename from build.rs rename to UNUSED.rs From f933d08863493d5b6bb4ae4b82c279b9dac9ab7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 16:58:32 +0100 Subject: [PATCH 288/315] Revert to build.rs --- UNUSED.rs => build.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename UNUSED.rs => build.rs (91%) diff --git a/UNUSED.rs b/build.rs similarity index 91% rename from UNUSED.rs rename to build.rs index 8ff787c..15825b8 100644 --- a/UNUSED.rs +++ b/build.rs @@ -1,4 +1,4 @@ -/* use std::path::PathBuf; +use std::path::PathBuf; use std::{env, fs}; fn main() { @@ -7,5 +7,4 @@ fn main() { println!("cargo:rustc-link-search={}", out_dir.display()); fs::copy("interrupts.x", out_dir.join("interrupts.x")).unwrap(); println!("cargo:rerun-if-changed=interrupts.x"); -} - */ \ No newline at end of file +} \ No newline at end of file From c9e70f5ed9d4f77bed2270980f58ecdace1d9e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Mon, 12 Dec 2022 17:19:59 +0100 Subject: [PATCH 289/315] Fix wrong comment type in .x --- interrupts.x | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interrupts.x b/interrupts.x index 9e28ce7..82eadac 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,6 +1,6 @@ /* Declare the external handlers array and the default handler as external symbols */ -// EXTERN(HANDLERS); -// EXTERN(DefaultMachineExternal); +/* EXTERN(HANDLERS); */ +/* EXTERN(DefaultMachineExternal); */ /* Provide the weak symbols for each interrupt handler */ PROVIDE(WATCHDOG = DefaultMachineExternal); PROVIDE(RTC = DefaultMachineExternal); From 3cadd18f1d741ebbfef8810b8f86d996324952f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Wed, 14 Dec 2022 15:57:08 +0100 Subject: [PATCH 290/315] code format and add a comment on .x --- build.rs | 2 +- interrupts.x | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 15825b8..35e87fd 100644 --- a/build.rs +++ b/build.rs @@ -7,4 +7,4 @@ fn main() { println!("cargo:rustc-link-search={}", out_dir.display()); fs::copy("interrupts.x", out_dir.join("interrupts.x")).unwrap(); println!("cargo:rerun-if-changed=interrupts.x"); -} \ No newline at end of file +} diff --git a/interrupts.x b/interrupts.x index 82eadac..1606066 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,6 +1,4 @@ -/* Declare the external handlers array and the default handler as external symbols */ -/* EXTERN(HANDLERS); */ -/* EXTERN(DefaultMachineExternal); */ +/* This file should be included by hifive1 */ /* Provide the weak symbols for each interrupt handler */ PROVIDE(WATCHDOG = DefaultMachineExternal); PROVIDE(RTC = DefaultMachineExternal); From cc0e48e055797985c5e93c3ccd8ccf5f90216505 Mon Sep 17 00:00:00 2001 From: yvt Date: Sat, 14 Jan 2023 21:25:54 +0900 Subject: [PATCH 291/315] Update `e310x` to `^0.10` and `riscv` to `^0.8` --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f2079bb..dcaf575 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,8 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -riscv = "0.7.0" -e310x = { version = "0.9.0", features = ["rt"] } +riscv = "0.8.0" +e310x = { version = "0.10.0", features = ["rt"] } [features] g002 = ["e310x/g002"] From 4f8f4295b1e9f1980ed03d22718fe253030fc235 Mon Sep 17 00:00:00 2001 From: yvt Date: Sun, 15 Jan 2023 18:25:18 +0900 Subject: [PATCH 292/315] Add changelog entries for `e310x` and `riscv` bump --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6762696..a07890d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist - Added Pulse Width Modulation interface implementing `embedded_hal::Pwm` +- Update `e310x` dependency to version 0.10 +- Update `riscv` dependency to version 0.8 ## [v0.9.4] - 2022-07-10 From ce823f9a9c7f80189f84240b67b750ba12ff72d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Fri, 17 Feb 2023 16:13:05 +0100 Subject: [PATCH 293/315] Bump riscv version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 83e37b0..deced23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -riscv = "0.7.0" +riscv = "0.8.0" e310x = { version = "0.10.0", features = ["rt"] } [features] From 612c737181dc7622bd5592cfd521c21c68abe7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Fri, 17 Feb 2023 16:30:18 +0100 Subject: [PATCH 294/315] Change travis CI for virq --- .github/workflows/ci.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4366937..3085fbf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,6 +32,8 @@ jobs: run: | cargo check --target riscv32imac-unknown-none-elf cargo check --target riscv32imac-unknown-none-elf --features g002 + cargo check --target riscv32imac-unknown-none-elf --features virq + cargo check --target riscv32imac-unknown-none-elf --features g002,virq # On macOS and Windows, we at least make sure that the crate builds and links. build-other: @@ -52,4 +54,6 @@ jobs: - name: Build crate for host OS run: | cargo build - cargo build --features g002 \ No newline at end of file + cargo build --features g002 + cargo build --features virq + cargo build --features g002,virq \ No newline at end of file From eaee9ebc9faf8f107688656f3f86e3109706b81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Sat, 18 Feb 2023 22:49:02 +0100 Subject: [PATCH 295/315] Naming --- .vscode/settings.json | 10 +++ CHANGELOG.md | 2 + Cargo.toml | 2 +- interrupts.x | 113 ++++++++++++----------- src/exthandler.rs | 105 ---------------------- src/interrupt.rs | 203 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- 7 files changed, 277 insertions(+), 162 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 src/exthandler.rs create mode 100644 src/interrupt.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2781fab --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true + }, + "rust-analyzer.cargo.features": [ + "g002", + "virq", + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6762696..b4b93a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist - Added Pulse Width Modulation interface implementing `embedded_hal::Pwm` +- Added `interrupt` module for vectored interrupt handlers. +This module is only active if feature `virq` is selected. ## [v0.9.4] - 2022-07-10 diff --git a/Cargo.toml b/Cargo.toml index deced23..071c5f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,4 @@ g002 = ["e310x/g002"] virq = [] [package.metadata.docs.rs] -features = ["g002"] +features = ["g002", "virq"] diff --git a/interrupts.x b/interrupts.x index 1606066..1dced2e 100644 --- a/interrupts.x +++ b/interrupts.x @@ -1,54 +1,59 @@ -/* This file should be included by hifive1 */ -/* Provide the weak symbols for each interrupt handler */ -PROVIDE(WATCHDOG = DefaultMachineExternal); -PROVIDE(RTC = DefaultMachineExternal); -PROVIDE(UART0 = DefaultMachineExternal); -PROVIDE(UART1 = DefaultMachineExternal); -PROVIDE(QSPI0 = DefaultMachineExternal); -PROVIDE(QSPI1 = DefaultMachineExternal); -PROVIDE(QSPI2 = DefaultMachineExternal); -PROVIDE(GPIO0 = DefaultMachineExternal); -PROVIDE(GPIO1 = DefaultMachineExternal); -PROVIDE(GPIO2 = DefaultMachineExternal); -PROVIDE(GPIO3 = DefaultMachineExternal); -PROVIDE(GPIO4 = DefaultMachineExternal); -PROVIDE(GPIO5 = DefaultMachineExternal); -PROVIDE(GPIO6 = DefaultMachineExternal); -PROVIDE(GPIO7 = DefaultMachineExternal); -PROVIDE(GPIO8 = DefaultMachineExternal); -PROVIDE(GPIO9 = DefaultMachineExternal); -PROVIDE(GPIO10 = DefaultMachineExternal); -PROVIDE(GPIO11 = DefaultMachineExternal); -PROVIDE(GPIO12 = DefaultMachineExternal); -PROVIDE(GPIO13 = DefaultMachineExternal); -PROVIDE(GPIO14 = DefaultMachineExternal); -PROVIDE(GPIO15 = DefaultMachineExternal); -PROVIDE(GPIO16 = DefaultMachineExternal); -PROVIDE(GPIO17 = DefaultMachineExternal); -PROVIDE(GPIO18 = DefaultMachineExternal); -PROVIDE(GPIO19 = DefaultMachineExternal); -PROVIDE(GPIO20 = DefaultMachineExternal); -PROVIDE(GPIO21 = DefaultMachineExternal); -PROVIDE(GPIO22 = DefaultMachineExternal); -PROVIDE(GPIO23 = DefaultMachineExternal); -PROVIDE(GPIO24 = DefaultMachineExternal); -PROVIDE(GPIO25 = DefaultMachineExternal); -PROVIDE(GPIO26 = DefaultMachineExternal); -PROVIDE(GPIO27 = DefaultMachineExternal); -PROVIDE(GPIO28 = DefaultMachineExternal); -PROVIDE(GPIO29 = DefaultMachineExternal); -PROVIDE(GPIO30 = DefaultMachineExternal); -PROVIDE(GPIO31 = DefaultMachineExternal); -PROVIDE(PWM0CMP0 = DefaultMachineExternal); -PROVIDE(PWM0CMP1 = DefaultMachineExternal); -PROVIDE(PWM0CMP2 = DefaultMachineExternal); -PROVIDE(PWM0CMP3 = DefaultMachineExternal); -PROVIDE(PWM1CMP0 = DefaultMachineExternal); -PROVIDE(PWM1CMP1 = DefaultMachineExternal); -PROVIDE(PWM1CMP2 = DefaultMachineExternal); -PROVIDE(PWM1CMP3 = DefaultMachineExternal); -PROVIDE(PWM2CMP0 = DefaultMachineExternal); -PROVIDE(PWM2CMP1 = DefaultMachineExternal); -PROVIDE(PWM2CMP2 = DefaultMachineExternal); -PROVIDE(PWM2CMP3 = DefaultMachineExternal); -PROVIDE(I2C0 = DefaultMachineExternal); +/* This file should be included by hifive1 if virq feature is enabled */ + +/* Weak symbol for other machine external interrupts handler */ +PROVIDE(OtherMachineExternal = DefaultMachineExternal); + +/* Weak symbols for each external interrupt handler */ +PROVIDE(WATCHDOG = OtherMachineExternal); +PROVIDE(RTC = OtherMachineExternal); +PROVIDE(UART0 = OtherMachineExternal); +PROVIDE(UART1 = OtherMachineExternal); +PROVIDE(QSPI0 = OtherMachineExternal); +PROVIDE(QSPI1 = OtherMachineExternal); +PROVIDE(QSPI2 = OtherMachineExternal); +PROVIDE(GPIO0 = OtherMachineExternal); +PROVIDE(GPIO1 = OtherMachineExternal); +PROVIDE(GPIO2 = OtherMachineExternal); +PROVIDE(GPIO3 = OtherMachineExternal); +PROVIDE(GPIO4 = OtherMachineExternal); +PROVIDE(GPIO5 = OtherMachineExternal); +PROVIDE(GPIO6 = OtherMachineExternal); +PROVIDE(GPIO7 = OtherMachineExternal); +PROVIDE(GPIO8 = OtherMachineExternal); +PROVIDE(GPIO9 = OtherMachineExternal); +PROVIDE(GPIO10 = OtherMachineExternal); +PROVIDE(GPIO11 = OtherMachineExternal); +PROVIDE(GPIO12 = OtherMachineExternal); +PROVIDE(GPIO13 = OtherMachineExternal); +PROVIDE(GPIO14 = OtherMachineExternal); +PROVIDE(GPIO15 = OtherMachineExternal); +PROVIDE(GPIO16 = OtherMachineExternal); +PROVIDE(GPIO17 = OtherMachineExternal); +PROVIDE(GPIO18 = OtherMachineExternal); +PROVIDE(GPIO19 = OtherMachineExternal); +PROVIDE(GPIO20 = OtherMachineExternal); +PROVIDE(GPIO21 = OtherMachineExternal); +PROVIDE(GPIO22 = OtherMachineExternal); +PROVIDE(GPIO23 = OtherMachineExternal); +PROVIDE(GPIO24 = OtherMachineExternal); +PROVIDE(GPIO25 = OtherMachineExternal); +PROVIDE(GPIO26 = OtherMachineExternal); +PROVIDE(GPIO27 = OtherMachineExternal); +PROVIDE(GPIO28 = OtherMachineExternal); +PROVIDE(GPIO29 = OtherMachineExternal); +PROVIDE(GPIO30 = OtherMachineExternal); +PROVIDE(GPIO31 = OtherMachineExternal); +PROVIDE(PWM0CMP0 = OtherMachineExternal); +PROVIDE(PWM0CMP1 = OtherMachineExternal); +PROVIDE(PWM0CMP2 = OtherMachineExternal); +PROVIDE(PWM0CMP3 = OtherMachineExternal); +PROVIDE(PWM1CMP0 = OtherMachineExternal); +PROVIDE(PWM1CMP1 = OtherMachineExternal); +PROVIDE(PWM1CMP2 = OtherMachineExternal); +PROVIDE(PWM1CMP3 = OtherMachineExternal); +PROVIDE(PWM2CMP0 = OtherMachineExternal); +PROVIDE(PWM2CMP1 = OtherMachineExternal); +PROVIDE(PWM2CMP2 = OtherMachineExternal); +PROVIDE(PWM2CMP3 = OtherMachineExternal); +/* Weak symbol for I2C0 (g002 only) */ +PROVIDE(I2C0 = OtherMachineExternal); diff --git a/src/exthandler.rs b/src/exthandler.rs deleted file mode 100644 index 210b156..0000000 --- a/src/exthandler.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Optional external interrupt handler -#[allow(unused)] -use crate::core::CorePeripherals; - -/* Empty definition of all external handler functions, provided -in interrupts.x. Can be overwritten by the user. */ -extern "C" { - fn WATCHDOG(); - fn RTC(); - fn UART0(); - fn UART1(); - fn QSPI0(); - fn QSPI1(); - fn QSPI2(); - fn GPIO0(); - fn GPIO1(); - fn GPIO2(); - fn GPIO3(); - fn GPIO4(); - fn GPIO5(); - fn GPIO6(); - fn GPIO7(); - fn GPIO8(); - fn GPIO9(); - fn GPIO10(); - fn GPIO11(); - fn GPIO12(); - fn GPIO13(); - fn GPIO14(); - fn GPIO15(); - fn GPIO16(); - fn GPIO17(); - fn GPIO18(); - fn GPIO19(); - fn GPIO20(); - fn GPIO21(); - fn GPIO22(); - fn GPIO23(); - fn GPIO24(); - fn GPIO25(); - fn GPIO26(); - fn GPIO27(); - fn GPIO28(); - fn GPIO29(); - fn GPIO30(); - fn GPIO31(); - fn PWM0CMP0(); - fn PWM0CMP1(); - fn PWM0CMP2(); - fn PWM0CMP3(); - fn PWM1CMP0(); - fn PWM1CMP1(); - fn PWM1CMP2(); - fn PWM1CMP3(); - fn PWM2CMP0(); - fn PWM2CMP1(); - fn PWM2CMP2(); - fn PWM2CMP3(); - fn I2C0(); -} - -#[no_mangle] -/// Array of handlers -pub static HANDLERS: [unsafe extern "C" fn(); 52] = [ - WATCHDOG, RTC, UART0, UART1, QSPI0, QSPI1, QSPI2, GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, - GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13, GPIO14, GPIO15, GPIO16, GPIO17, - GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, GPIO24, GPIO25, GPIO26, GPIO27, GPIO28, GPIO29, - GPIO30, GPIO31, PWM0CMP0, PWM0CMP1, PWM0CMP2, PWM0CMP3, PWM1CMP0, PWM1CMP1, PWM1CMP2, PWM1CMP3, - PWM2CMP0, PWM2CMP1, PWM2CMP2, PWM2CMP3, I2C0, -]; - -#[no_mangle] -#[allow(non_snake_case)] -/// Default external handler -pub fn DefaultMachineExternal() { - loop { - /* do nothing, but we need a side effect so LLVM does not optimize - this */ - continue; - } -} -/// Optional handler to use for external interrupts. -/// It will automatically claim any interrupt and call the appropriate -/// handler function (ex.: GPIO0() for GPIO0 interrupts). -/// The handler functions can be overriden by the user, otherwise default -/// behavior will be called. -#[no_mangle] -#[allow(non_snake_case)] -unsafe fn MachineExternal() { - /* Steal the PLIC peripheral to claim the interrupt */ - let mut plic = CorePeripherals::steal().plic; - let interrupt = plic.claim.claim().unwrap(); - /* Match the appropriate external interrupt */ - /* Interrupt 0 is defined as no interrupt, so we treat it independently */ - if interrupt as usize == 0 { - DefaultMachineExternal() - } else if (interrupt as usize) < HANDLERS.len() && (interrupt as usize > 0) { - // Offset the handlers as we do not work with interrupt = 0 - HANDLERS[(interrupt as usize) - 1](); - } else { - return; - } - // Claim PLIC interrupt source as complete by this handler - plic.claim.complete(interrupt); -} diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..45f2c4e --- /dev/null +++ b/src/interrupt.rs @@ -0,0 +1,203 @@ +//! Vectored machine external interrupt handler. +//! +//! # Notes +//! +//! - You must activate the `virq` feature to use this module. +//! +//! - The vectored handler automatically claims the PLIC interrupt source as complete. +//! Thus, users do not have to worry about this step. +//! +//! # Features +//! +//! This module provides: +//! +//! - A vectored implementation for handling each machine external interrupt source independently. +//! +//! - A linker script that provides weak symbols for all the interrupt sources of an E310X microcontroller. +//! This file must be supplied using rustflag when compiling. +//! +//! # Implementation details +//! +//! You can define a custom handler for each interrupt source (see [`e310x::interrupt::Interrupt`]). +//! For instance, if you want to define a custom handler for interrupts triggered by +//! the [`e310x::interrupt::Interrupt::GPIO0`] source, you must define the `GPIO0` function: +//! +//! ```ignore +//! #[no_mangle] +//! #[allow(non_snake_case)] +//! fn GPIO0() { +//! // define the behavior of your custom handler +//! } +//! ``` +//! +//! Note that the function must be marked as `no_mangle`. +//! You can also use the [`e310x::interrupt!`] macro. +//! +//! If a source without custom handler triggers an interruption, it executes the +//! `OtherMachineExternal` handler. This handler function is shared among all the +//! undefined interrupt sources. You can define this handler as follows: +//! +//! ```ignore,no_run +//! #[no_mangle] +//! #[allow(non_snake_case)] +//! fn OtherMachineExternal() { +//! // define the behavior of this handler +//! } +//! ``` +//! +//! By default, `OtherMachineExternal` executes the [`DefaultMachineExternal`] handler. +//! This handler is just an infinite loop. + +use crate::core::CorePeripherals; +pub use e310x::interrupt::*; + +extern "C" { + fn WATCHDOG(); + fn RTC(); + fn UART0(); + fn UART1(); + fn QSPI0(); + fn QSPI1(); + fn QSPI2(); + fn GPIO0(); + fn GPIO1(); + fn GPIO2(); + fn GPIO3(); + fn GPIO4(); + fn GPIO5(); + fn GPIO6(); + fn GPIO7(); + fn GPIO8(); + fn GPIO9(); + fn GPIO10(); + fn GPIO11(); + fn GPIO12(); + fn GPIO13(); + fn GPIO14(); + fn GPIO15(); + fn GPIO16(); + fn GPIO17(); + fn GPIO18(); + fn GPIO19(); + fn GPIO20(); + fn GPIO21(); + fn GPIO22(); + fn GPIO23(); + fn GPIO24(); + fn GPIO25(); + fn GPIO26(); + fn GPIO27(); + fn GPIO28(); + fn GPIO29(); + fn GPIO30(); + fn GPIO31(); + fn PWM0CMP0(); + fn PWM0CMP1(); + fn PWM0CMP2(); + fn PWM0CMP3(); + fn PWM1CMP0(); + fn PWM1CMP1(); + fn PWM1CMP2(); + fn PWM1CMP3(); + fn PWM2CMP0(); + fn PWM2CMP1(); + fn PWM2CMP2(); + fn PWM2CMP3(); + #[cfg(feature = "g002")] + fn I2C0(); +} + +#[no_mangle] +#[allow(non_snake_case)] +/// Default machine external interrupt handler. It is an infinite loop. +pub fn DefaultMachineExternal() { + loop { + // Prevent this from turning into a UDF instruction + // see rust-lang/rust#28728 for details + continue; + } +} + +#[cfg(not(feature = "g002"))] +const N_INTERRUPTS: usize = 51; +#[cfg(feature = "g002")] +const N_INTERRUPTS: usize = 52; + +/// Array of machine external interrupt handlers. +static HANDLERS: [unsafe extern "C" fn(); N_INTERRUPTS] = [ + WATCHDOG, + RTC, + UART0, + UART1, + QSPI0, + QSPI1, + QSPI2, + GPIO0, + GPIO1, + GPIO2, + GPIO3, + GPIO4, + GPIO5, + GPIO6, + GPIO7, + GPIO8, + GPIO9, + GPIO10, + GPIO11, + GPIO12, + GPIO13, + GPIO14, + GPIO15, + GPIO16, + GPIO17, + GPIO18, + GPIO19, + GPIO20, + GPIO21, + GPIO22, + GPIO23, + GPIO24, + GPIO25, + GPIO26, + GPIO27, + GPIO28, + GPIO29, + GPIO30, + GPIO31, + PWM0CMP0, + PWM0CMP1, + PWM0CMP2, + PWM0CMP3, + PWM1CMP0, + PWM1CMP1, + PWM1CMP2, + PWM1CMP3, + PWM2CMP0, + PWM2CMP1, + PWM2CMP2, + PWM2CMP3, + #[cfg(feature = "g002")] + I2C0, +]; + +/// Handler for vectored machine external interrupts (see the [`riscv-rt`] crate). +#[no_mangle] +#[allow(non_snake_case)] +unsafe fn MachineExternal() { + // Steal the PLIC peripheral and claim the interrupt + let mut plic = CorePeripherals::steal().plic; + let interrupt = plic.claim.claim().unwrap(); + let interrupt_n = interrupt as usize; + // Match the appropriate machine external interrupt + if interrupt_n == 0 { + // Interrupt number 0 is defined as no interrupt + } else if interrupt_n <= HANDLERS.len() { + // Execute corresponding interrupt handler + HANDLERS[interrupt_n - 1](); + } else { + // Any other interrupt number is not allowed + DefaultMachineExternal(); + } + // Claim PLIC interrupt source as complete by this handler + plic.claim.complete(interrupt); +} diff --git a/src/lib.rs b/src/lib.rs index 445054b..b0f50b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,6 @@ pub mod clock; pub mod core; pub mod delay; pub mod device; -#[cfg(feature = "virq")] -pub mod exthandler; pub mod gpio; pub mod pmu; pub mod prelude; @@ -27,5 +25,7 @@ pub mod wdog; #[cfg(feature = "g002")] pub mod i2c; +#[cfg(feature = "virq")] +pub mod interrupt; pub use device::DeviceResources; From fb581299e9543f28298de8d525dca77c8af96c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=C3=A9rez?= Date: Tue, 21 Feb 2023 14:41:15 +0100 Subject: [PATCH 296/315] rename virq linker script --- build.rs | 4 ++-- fe310x-interrupt.x | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 fe310x-interrupt.x diff --git a/build.rs b/build.rs index 35e87fd..6694100 100644 --- a/build.rs +++ b/build.rs @@ -5,6 +5,6 @@ fn main() { // Put the linker script somewhere the linker can find it let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); println!("cargo:rustc-link-search={}", out_dir.display()); - fs::copy("interrupts.x", out_dir.join("interrupts.x")).unwrap(); - println!("cargo:rerun-if-changed=interrupts.x"); + fs::copy("fe310x-interrupt.x", out_dir.join("fe310x-interrupt.x")).unwrap(); + println!("cargo:rerun-if-changed=fe310x-interrupt.x"); } diff --git a/fe310x-interrupt.x b/fe310x-interrupt.x new file mode 100644 index 0000000..1dced2e --- /dev/null +++ b/fe310x-interrupt.x @@ -0,0 +1,59 @@ +/* This file should be included by hifive1 if virq feature is enabled */ + +/* Weak symbol for other machine external interrupts handler */ +PROVIDE(OtherMachineExternal = DefaultMachineExternal); + +/* Weak symbols for each external interrupt handler */ +PROVIDE(WATCHDOG = OtherMachineExternal); +PROVIDE(RTC = OtherMachineExternal); +PROVIDE(UART0 = OtherMachineExternal); +PROVIDE(UART1 = OtherMachineExternal); +PROVIDE(QSPI0 = OtherMachineExternal); +PROVIDE(QSPI1 = OtherMachineExternal); +PROVIDE(QSPI2 = OtherMachineExternal); +PROVIDE(GPIO0 = OtherMachineExternal); +PROVIDE(GPIO1 = OtherMachineExternal); +PROVIDE(GPIO2 = OtherMachineExternal); +PROVIDE(GPIO3 = OtherMachineExternal); +PROVIDE(GPIO4 = OtherMachineExternal); +PROVIDE(GPIO5 = OtherMachineExternal); +PROVIDE(GPIO6 = OtherMachineExternal); +PROVIDE(GPIO7 = OtherMachineExternal); +PROVIDE(GPIO8 = OtherMachineExternal); +PROVIDE(GPIO9 = OtherMachineExternal); +PROVIDE(GPIO10 = OtherMachineExternal); +PROVIDE(GPIO11 = OtherMachineExternal); +PROVIDE(GPIO12 = OtherMachineExternal); +PROVIDE(GPIO13 = OtherMachineExternal); +PROVIDE(GPIO14 = OtherMachineExternal); +PROVIDE(GPIO15 = OtherMachineExternal); +PROVIDE(GPIO16 = OtherMachineExternal); +PROVIDE(GPIO17 = OtherMachineExternal); +PROVIDE(GPIO18 = OtherMachineExternal); +PROVIDE(GPIO19 = OtherMachineExternal); +PROVIDE(GPIO20 = OtherMachineExternal); +PROVIDE(GPIO21 = OtherMachineExternal); +PROVIDE(GPIO22 = OtherMachineExternal); +PROVIDE(GPIO23 = OtherMachineExternal); +PROVIDE(GPIO24 = OtherMachineExternal); +PROVIDE(GPIO25 = OtherMachineExternal); +PROVIDE(GPIO26 = OtherMachineExternal); +PROVIDE(GPIO27 = OtherMachineExternal); +PROVIDE(GPIO28 = OtherMachineExternal); +PROVIDE(GPIO29 = OtherMachineExternal); +PROVIDE(GPIO30 = OtherMachineExternal); +PROVIDE(GPIO31 = OtherMachineExternal); +PROVIDE(PWM0CMP0 = OtherMachineExternal); +PROVIDE(PWM0CMP1 = OtherMachineExternal); +PROVIDE(PWM0CMP2 = OtherMachineExternal); +PROVIDE(PWM0CMP3 = OtherMachineExternal); +PROVIDE(PWM1CMP0 = OtherMachineExternal); +PROVIDE(PWM1CMP1 = OtherMachineExternal); +PROVIDE(PWM1CMP2 = OtherMachineExternal); +PROVIDE(PWM1CMP3 = OtherMachineExternal); +PROVIDE(PWM2CMP0 = OtherMachineExternal); +PROVIDE(PWM2CMP1 = OtherMachineExternal); +PROVIDE(PWM2CMP2 = OtherMachineExternal); +PROVIDE(PWM2CMP3 = OtherMachineExternal); +/* Weak symbol for I2C0 (g002 only) */ +PROVIDE(I2C0 = OtherMachineExternal); From 99cfe9d19eaaebd60fcf674b5f6803fce47e2f42 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 3 Mar 2023 09:11:45 -0800 Subject: [PATCH 297/315] update to latest riscv crate --- Cargo.toml | 6 +++--- src/stdout.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 601da86..2f5fbd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ license = "ISC" edition = "2018" [dependencies] -e310x-hal = "0.9.1" -embedded-hal = "0.2.5" -riscv = "0.6.0" +e310x-hal = "0.9.3" +embedded-hal = "0.2.7" +riscv = "0.10.1" nb = "1.0.0" [features] diff --git a/src/stdout.rs b/src/stdout.rs index 68779d4..829cbbd 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -50,7 +50,7 @@ pub fn configure( let serial = Serial::new(uart, (tx, rx), baud_rate, clocks); let (tx, rx) = serial.split(); - interrupt::free(|_| unsafe { + interrupt::free(|| unsafe { STDOUT.replace(SerialWrapper(tx)); }); rx @@ -58,7 +58,7 @@ pub fn configure( /// Writes string to stdout pub fn write_str(s: &str) { - interrupt::free(|_| unsafe { + interrupt::free(|| unsafe { if let Some(stdout) = STDOUT.as_mut() { let _ = stdout.write_str(s); } @@ -67,7 +67,7 @@ pub fn write_str(s: &str) { /// Writes formatted string to stdout pub fn write_fmt(args: fmt::Arguments) { - interrupt::free(|_| unsafe { + interrupt::free(|| unsafe { if let Some(stdout) = STDOUT.as_mut() { let _ = stdout.write_fmt(args); } From 4b47b878d3e337b225f61ca49f29c029919bd5de Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 3 Mar 2023 09:14:13 -0800 Subject: [PATCH 298/315] add dependecy bump changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df48f2..0e89bed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- Updated riscv dependency to v0.10 with interrupt/critical section changes + ## [v0.10.0] - 2021-07-15 ### Added From 87c2c051a7a60f7a7b0d59f453005a6ecfeef470 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 3 Mar 2023 09:19:51 -0800 Subject: [PATCH 299/315] bump MSRV to 1.59 due to dependencies --- .github/bors.toml | 2 +- .github/workflows/ci.yaml | 4 ++-- Cargo.toml | 1 + README.md | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/bors.toml b/.github/bors.toml index b5b4935..ca7d72a 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -3,7 +3,7 @@ delete_merged_branches = true required_approvals = 1 status = [ "ci-linux (stable)", - "ci-linux (1.42.0)", + "ci-linux (1.59.0)", "build-other (macOS-latest)", "build-other (windows-latest)", "Rustfmt" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3d9685b..8f219a4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.42.0 - rust: [nightly, stable, 1.42.0] + # All generated code should be running on stable now, MRSV is 1.59.0 + rust: [nightly, stable, 1.59.0] include: # Nightly is only for reference and allowed to fail diff --git a/Cargo.toml b/Cargo.toml index 2f5fbd2..20492e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ description = "Board support crate for HiFive1 and LoFive boards" keywords = ["riscv", "register", "peripheral"] license = "ISC" edition = "2018" +rust-version = "1.59" [dependencies] e310x-hal = "0.9.3" diff --git a/README.md b/README.md index 593b26c..a734eb5 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License -Copyright 2018-2019 [RISC-V team][team] +Copyright 2018-2023 [RISC-V team][team] Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice From c425cae00a3941365a2eff4124833cc6fac33618 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 3 Mar 2023 09:25:54 -0800 Subject: [PATCH 300/315] releave v0.11.0 --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e89bed..3506c4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.11.0] - 2023-03-03 + ### Changed - Updated riscv dependency to v0.10 with interrupt/critical section changes diff --git a/Cargo.toml b/Cargo.toml index 20492e7..efc832f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.10.0" +version = "0.11.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] From 230c44aa7e0787ec52020d629459352c98acacd9 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 28 Mar 2023 13:35:50 -0700 Subject: [PATCH 301/315] update e310x dependency to v0.11.0 --- Cargo.toml | 6 +++--- src/clock.rs | 2 +- src/spi/shared_bus.rs | 17 ++++++++--------- src/spi/shared_device.rs | 24 ++++++++++++------------ 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 071c5f5..b1fdfe9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.10.0" +version = "0.11.0" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -13,8 +13,8 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -riscv = "0.8.0" -e310x = { version = "0.10.0", features = ["rt"] } +riscv = "0.10.1" +e310x = { version = "0.11.0", features = ["rt", "critical-section"] } [features] g002 = ["e310x/g002"] diff --git a/src/clock.rs b/src/clock.rs index 2d8908b..b011cdd 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -386,7 +386,7 @@ impl Clocks { /// Measure the coreclk frequency by counting the number of aonclk ticks. fn _measure_coreclk(&self, min_ticks: u64) -> Hertz { let mtime = MTIME; - interrupt::free(|_| { + interrupt::free(|| { // Don't start measuring until we see an mtime tick while mtime.mtime() == mtime.mtime() {} diff --git a/src/spi/shared_bus.rs b/src/spi/shared_bus.rs index ab10025..67b9e06 100644 --- a/src/spi/shared_bus.rs +++ b/src/spi/shared_bus.rs @@ -2,13 +2,12 @@ use core::cell::RefCell; use core::ops::Deref; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use riscv::interrupt; -use riscv::interrupt::Mutex; use super::{PinCS, PinsNoCS, SpiBus, SpiConfig, SpiSharedDevice, SpiX}; /// Newtype for RefCell locked behind a Mutex. /// Used to hold the [SpiBus] instance so it can be used for multiple [SpiSharedDevice] instances. -pub struct SharedBus(Mutex>>); +pub struct SharedBus(RefCell>); impl SharedBus where @@ -16,7 +15,7 @@ where PINS: PinsNoCS, { pub(crate) fn new(bus: SpiBus) -> Self { - Self(Mutex::new(RefCell::new(bus))) + Self(RefCell::new(bus)) } /// Create a new shared device on this SPI bus. @@ -39,30 +38,30 @@ where { /// Set HOLD CS mode to per-frame operation, unless CSMODE is set to OFF pub fn start_frame(&mut self) { - interrupt::free(|cs| { - let mut bus = self.0.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.0.borrow_mut(); bus.start_frame(); }); } /// Finishes transfer by deasserting CS (only for hardware-controlled CS) pub fn end_frame(&mut self) { - interrupt::free(|cs| { - let mut bus = self.0.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.0.borrow_mut(); bus.end_frame(); }); } /// Releases the SPI peripheral and associated pins pub fn release(self) -> (SPI, PINS) { - let bus = self.0.into_inner().into_inner(); + let bus = self.0.into_inner(); (bus.spi, bus.pins) } } impl Deref for SharedBus { - type Target = Mutex>>; + type Target = RefCell>; fn deref(&self) -> &Self::Target { &self.0 diff --git a/src/spi/shared_device.rs b/src/spi/shared_device.rs index e611273..cbedea9 100644 --- a/src/spi/shared_device.rs +++ b/src/spi/shared_device.rs @@ -49,8 +49,8 @@ where type Error = Infallible; fn read(&mut self) -> nb::Result { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); @@ -59,8 +59,8 @@ where } fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); @@ -78,8 +78,8 @@ where type Error = Infallible; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - interrupt::free(move |cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(move || { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); @@ -101,8 +101,8 @@ where type Error = Infallible; fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); @@ -127,8 +127,8 @@ where where WI: IntoIterator, { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); @@ -150,8 +150,8 @@ where type Error = Infallible; fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); + interrupt::free(|| { + let mut bus = self.bus.borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); From 8f816dfd144099b29492922373bee3dca9c9934b Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 28 Mar 2023 15:19:49 -0700 Subject: [PATCH 302/315] remove unused interrupt linking info --- build.rs | 10 -------- fe310x-interrupt.x | 59 ---------------------------------------------- interrupts.x | 59 ---------------------------------------------- 3 files changed, 128 deletions(-) delete mode 100644 build.rs delete mode 100644 fe310x-interrupt.x delete mode 100644 interrupts.x diff --git a/build.rs b/build.rs deleted file mode 100644 index 6694100..0000000 --- a/build.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::path::PathBuf; -use std::{env, fs}; - -fn main() { - // Put the linker script somewhere the linker can find it - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - println!("cargo:rustc-link-search={}", out_dir.display()); - fs::copy("fe310x-interrupt.x", out_dir.join("fe310x-interrupt.x")).unwrap(); - println!("cargo:rerun-if-changed=fe310x-interrupt.x"); -} diff --git a/fe310x-interrupt.x b/fe310x-interrupt.x deleted file mode 100644 index 1dced2e..0000000 --- a/fe310x-interrupt.x +++ /dev/null @@ -1,59 +0,0 @@ -/* This file should be included by hifive1 if virq feature is enabled */ - -/* Weak symbol for other machine external interrupts handler */ -PROVIDE(OtherMachineExternal = DefaultMachineExternal); - -/* Weak symbols for each external interrupt handler */ -PROVIDE(WATCHDOG = OtherMachineExternal); -PROVIDE(RTC = OtherMachineExternal); -PROVIDE(UART0 = OtherMachineExternal); -PROVIDE(UART1 = OtherMachineExternal); -PROVIDE(QSPI0 = OtherMachineExternal); -PROVIDE(QSPI1 = OtherMachineExternal); -PROVIDE(QSPI2 = OtherMachineExternal); -PROVIDE(GPIO0 = OtherMachineExternal); -PROVIDE(GPIO1 = OtherMachineExternal); -PROVIDE(GPIO2 = OtherMachineExternal); -PROVIDE(GPIO3 = OtherMachineExternal); -PROVIDE(GPIO4 = OtherMachineExternal); -PROVIDE(GPIO5 = OtherMachineExternal); -PROVIDE(GPIO6 = OtherMachineExternal); -PROVIDE(GPIO7 = OtherMachineExternal); -PROVIDE(GPIO8 = OtherMachineExternal); -PROVIDE(GPIO9 = OtherMachineExternal); -PROVIDE(GPIO10 = OtherMachineExternal); -PROVIDE(GPIO11 = OtherMachineExternal); -PROVIDE(GPIO12 = OtherMachineExternal); -PROVIDE(GPIO13 = OtherMachineExternal); -PROVIDE(GPIO14 = OtherMachineExternal); -PROVIDE(GPIO15 = OtherMachineExternal); -PROVIDE(GPIO16 = OtherMachineExternal); -PROVIDE(GPIO17 = OtherMachineExternal); -PROVIDE(GPIO18 = OtherMachineExternal); -PROVIDE(GPIO19 = OtherMachineExternal); -PROVIDE(GPIO20 = OtherMachineExternal); -PROVIDE(GPIO21 = OtherMachineExternal); -PROVIDE(GPIO22 = OtherMachineExternal); -PROVIDE(GPIO23 = OtherMachineExternal); -PROVIDE(GPIO24 = OtherMachineExternal); -PROVIDE(GPIO25 = OtherMachineExternal); -PROVIDE(GPIO26 = OtherMachineExternal); -PROVIDE(GPIO27 = OtherMachineExternal); -PROVIDE(GPIO28 = OtherMachineExternal); -PROVIDE(GPIO29 = OtherMachineExternal); -PROVIDE(GPIO30 = OtherMachineExternal); -PROVIDE(GPIO31 = OtherMachineExternal); -PROVIDE(PWM0CMP0 = OtherMachineExternal); -PROVIDE(PWM0CMP1 = OtherMachineExternal); -PROVIDE(PWM0CMP2 = OtherMachineExternal); -PROVIDE(PWM0CMP3 = OtherMachineExternal); -PROVIDE(PWM1CMP0 = OtherMachineExternal); -PROVIDE(PWM1CMP1 = OtherMachineExternal); -PROVIDE(PWM1CMP2 = OtherMachineExternal); -PROVIDE(PWM1CMP3 = OtherMachineExternal); -PROVIDE(PWM2CMP0 = OtherMachineExternal); -PROVIDE(PWM2CMP1 = OtherMachineExternal); -PROVIDE(PWM2CMP2 = OtherMachineExternal); -PROVIDE(PWM2CMP3 = OtherMachineExternal); -/* Weak symbol for I2C0 (g002 only) */ -PROVIDE(I2C0 = OtherMachineExternal); diff --git a/interrupts.x b/interrupts.x deleted file mode 100644 index 1dced2e..0000000 --- a/interrupts.x +++ /dev/null @@ -1,59 +0,0 @@ -/* This file should be included by hifive1 if virq feature is enabled */ - -/* Weak symbol for other machine external interrupts handler */ -PROVIDE(OtherMachineExternal = DefaultMachineExternal); - -/* Weak symbols for each external interrupt handler */ -PROVIDE(WATCHDOG = OtherMachineExternal); -PROVIDE(RTC = OtherMachineExternal); -PROVIDE(UART0 = OtherMachineExternal); -PROVIDE(UART1 = OtherMachineExternal); -PROVIDE(QSPI0 = OtherMachineExternal); -PROVIDE(QSPI1 = OtherMachineExternal); -PROVIDE(QSPI2 = OtherMachineExternal); -PROVIDE(GPIO0 = OtherMachineExternal); -PROVIDE(GPIO1 = OtherMachineExternal); -PROVIDE(GPIO2 = OtherMachineExternal); -PROVIDE(GPIO3 = OtherMachineExternal); -PROVIDE(GPIO4 = OtherMachineExternal); -PROVIDE(GPIO5 = OtherMachineExternal); -PROVIDE(GPIO6 = OtherMachineExternal); -PROVIDE(GPIO7 = OtherMachineExternal); -PROVIDE(GPIO8 = OtherMachineExternal); -PROVIDE(GPIO9 = OtherMachineExternal); -PROVIDE(GPIO10 = OtherMachineExternal); -PROVIDE(GPIO11 = OtherMachineExternal); -PROVIDE(GPIO12 = OtherMachineExternal); -PROVIDE(GPIO13 = OtherMachineExternal); -PROVIDE(GPIO14 = OtherMachineExternal); -PROVIDE(GPIO15 = OtherMachineExternal); -PROVIDE(GPIO16 = OtherMachineExternal); -PROVIDE(GPIO17 = OtherMachineExternal); -PROVIDE(GPIO18 = OtherMachineExternal); -PROVIDE(GPIO19 = OtherMachineExternal); -PROVIDE(GPIO20 = OtherMachineExternal); -PROVIDE(GPIO21 = OtherMachineExternal); -PROVIDE(GPIO22 = OtherMachineExternal); -PROVIDE(GPIO23 = OtherMachineExternal); -PROVIDE(GPIO24 = OtherMachineExternal); -PROVIDE(GPIO25 = OtherMachineExternal); -PROVIDE(GPIO26 = OtherMachineExternal); -PROVIDE(GPIO27 = OtherMachineExternal); -PROVIDE(GPIO28 = OtherMachineExternal); -PROVIDE(GPIO29 = OtherMachineExternal); -PROVIDE(GPIO30 = OtherMachineExternal); -PROVIDE(GPIO31 = OtherMachineExternal); -PROVIDE(PWM0CMP0 = OtherMachineExternal); -PROVIDE(PWM0CMP1 = OtherMachineExternal); -PROVIDE(PWM0CMP2 = OtherMachineExternal); -PROVIDE(PWM0CMP3 = OtherMachineExternal); -PROVIDE(PWM1CMP0 = OtherMachineExternal); -PROVIDE(PWM1CMP1 = OtherMachineExternal); -PROVIDE(PWM1CMP2 = OtherMachineExternal); -PROVIDE(PWM1CMP3 = OtherMachineExternal); -PROVIDE(PWM2CMP0 = OtherMachineExternal); -PROVIDE(PWM2CMP1 = OtherMachineExternal); -PROVIDE(PWM2CMP2 = OtherMachineExternal); -PROVIDE(PWM2CMP3 = OtherMachineExternal); -/* Weak symbol for I2C0 (g002 only) */ -PROVIDE(I2C0 = OtherMachineExternal); From 65fcbbb394b6da3abe49f81a6a5f7e070859b0f4 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 28 Mar 2023 15:19:57 -0700 Subject: [PATCH 303/315] release v0.10.0 --- CHANGELOG.md | 17 ++++++++++++----- Cargo.toml | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb043c..b689799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -- Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist +## [v0.10.0] - 2023-03-28 + +### Added - Added Pulse Width Modulation interface implementing `embedded_hal::Pwm` -- Added `interrupt` module for vectored interrupt handlers. -This module is only active if feature `virq` is selected. -- Update `e310x` dependency to version 0.10 -- Update `riscv` dependency to version 0.8 +- Added `interrupt` module for vectored interrupt handlers. This module is only active if feature `virq` is selected. + +### Changed +- Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist +- Update `e310x` dependency to version 0.11 +- Update `riscv` dependency to version 0.10 + +### Removed +- removed interrupt linking definitions, they are now provided by `e310x` via `svd2rust` ## [v0.9.4] - 2022-07-10 diff --git a/Cargo.toml b/Cargo.toml index b1fdfe9..017b8aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -riscv = "0.10.1" +riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } e310x = { version = "0.11.0", features = ["rt", "critical-section"] } [features] From d73593394c8f8eaccd22942912dd2b59ca57bec0 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Tue, 28 Mar 2023 15:25:07 -0700 Subject: [PATCH 304/315] release v0.12.0 with updated dependencies --- CHANGELOG.md | 3 +++ Cargo.toml | 4 ++-- memory-hifive1-revb.x | 2 +- memory-hifive1.x | 2 +- memory-lofive-r1.x | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3506c4f..99d128e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.12.0] - 2023-03-28 +- Update e310x-hal to v0.11 with new svd2rust generated code + ## [v0.11.0] - 2023-03-03 ### Changed diff --git a/Cargo.toml b/Cargo.toml index efc832f..d875ffd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hifive1" -version = "0.11.0" +version = "0.12.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] @@ -11,7 +11,7 @@ edition = "2018" rust-version = "1.59" [dependencies] -e310x-hal = "0.9.3" +e310x-hal = "0.11.0" embedded-hal = "0.2.7" riscv = "0.10.1" nb = "1.0.0" diff --git a/memory-hifive1-revb.x b/memory-hifive1-revb.x index e9e4bc5..4239af3 100644 --- a/memory-hifive1-revb.x +++ b/memory-hifive1-revb.x @@ -1,4 +1,4 @@ -INCLUDE memory-fe310.x +INCLUDE device.x MEMORY { FLASH : ORIGIN = 0x20000000, LENGTH = 4M diff --git a/memory-hifive1.x b/memory-hifive1.x index cd55c70..e5dc86e 100644 --- a/memory-hifive1.x +++ b/memory-hifive1.x @@ -1,4 +1,4 @@ -INCLUDE memory-fe310.x +INCLUDE device.x MEMORY { FLASH : ORIGIN = 0x20000000, LENGTH = 16M diff --git a/memory-lofive-r1.x b/memory-lofive-r1.x index cd55c70..e5dc86e 100644 --- a/memory-lofive-r1.x +++ b/memory-lofive-r1.x @@ -1,4 +1,4 @@ -INCLUDE memory-fe310.x +INCLUDE device.x MEMORY { FLASH : ORIGIN = 0x20000000, LENGTH = 16M From 9345570c958eef6141fd526b85a076a99fed66bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Thu, 29 Jun 2023 18:14:20 +0200 Subject: [PATCH 305/315] use atomic-polyfill --- .github/workflows/ci.yaml | 6 +++++- CHANGELOG.md | 2 ++ Cargo.toml | 1 + src/gpio.rs | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3085fbf..5311dd0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,13 +27,17 @@ jobs: toolchain: ${{ matrix.rust }} override: true - name: Install all Rust targets for ${{ matrix.rust }} - run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf + run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv32imc-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} run: | cargo check --target riscv32imac-unknown-none-elf cargo check --target riscv32imac-unknown-none-elf --features g002 cargo check --target riscv32imac-unknown-none-elf --features virq cargo check --target riscv32imac-unknown-none-elf --features g002,virq + cargo check --target riscv32imc-unknown-none-elf + cargo check --target riscv32imc-unknown-none-elf --features g002 + cargo check --target riscv32imc-unknown-none-elf --features virq + cargo check --target riscv32imc-unknown-none-elf --features g002,virq # On macOS and Windows, we at least make sure that the crate builds and links. build-other: diff --git a/CHANGELOG.md b/CHANGELOG.md index b689799..d8845f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Use `atomic-polyfill` to allow builds on riscv32imc-unknown-none-elf targets when needed. + ## [v0.10.0] - 2023-03-28 ### Added diff --git a/Cargo.toml b/Cargo.toml index 017b8aa..e30e4b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" +atomic-polyfill = "1.0.2" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } e310x = { version = "0.11.0", features = ["rt", "critical-section"] } diff --git a/src/gpio.rs b/src/gpio.rs index 63239f0..2be0d58 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,7 +1,7 @@ //! General Purpose I/O +use atomic_polyfill::{AtomicU32, Ordering}; use core::marker::PhantomData; -use core::sync::atomic::{AtomicU32, Ordering}; /// GpioExt trait extends the GPIO0 peripheral. pub trait GpioExt { From 6ab1d5173bf093d682fa03f0b46f5f9025a42771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Fri, 6 Oct 2023 18:06:17 +0200 Subject: [PATCH 306/315] Use portable-atomic --- Cargo.toml | 4 +++- src/gpio.rs | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e30e4b4..ca7141c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,10 +13,12 @@ rust-version = "1.59" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" -atomic-polyfill = "1.0.2" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } e310x = { version = "0.11.0", features = ["rt", "critical-section"] } +[target.'cfg(not(target_has_atomic = "32"))'.dependencies] +portable-atomic = { version = "1.4", default-features = false, features = ["unsafe-assume-single-core"] } + [features] g002 = ["e310x/g002"] virq = [] diff --git a/src/gpio.rs b/src/gpio.rs index 2be0d58..1061884 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,8 +1,12 @@ //! General Purpose I/O -use atomic_polyfill::{AtomicU32, Ordering}; use core::marker::PhantomData; +#[cfg(target_has_atomic = "32")] +use core::sync::atomic::{AtomicU32, Ordering}; +#[cfg(not(target_has_atomic = "32"))] +use portable_atomic::{AtomicU32, Ordering}; + /// GpioExt trait extends the GPIO0 peripheral. pub trait GpioExt { /// The parts to split the GPIO into. From 74541fa371ee1bd904b263cc7b4fdeb4dc1ef361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Fri, 6 Oct 2023 18:18:02 +0200 Subject: [PATCH 307/315] bump MSRV to 1.60 --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5311dd0..432c595 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.59.0 - rust: [nightly, stable, 1.59.0] + # All generated code should be running on stable now, MRSV is 1.60.0 + rust: [nightly, stable, 1.60.0] include: # Nightly is only for reference and allowed to fail From 4675f42954adf0c575443d976a15d9c2d512f83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Fri, 6 Oct 2023 18:24:07 +0200 Subject: [PATCH 308/315] changelog --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf2f875..fe081e8 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.60.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License From 902a4142e0682e52b8ba60553e23c336c730ec16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Fri, 6 Oct 2023 18:24:24 +0200 Subject: [PATCH 309/315] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8845f3..aa47fb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -- Use `atomic-polyfill` to allow builds on riscv32imc-unknown-none-elf targets when needed. +- Use `portable-atomic` to allow builds on `riscv32imc-unknown-none-elf`` targets when needed. ## [v0.10.0] - 2023-03-28 From 34655fe868510468850bbffcfa7678ed5798f160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Fri, 20 Sep 2024 13:04:19 +0200 Subject: [PATCH 310/315] prepare for workspace --- .github/CODEOWNERS | 1 - .github/bors.toml | 10 --- .github/workflows/ci.yaml | 63 ------------------- .github/workflows/rustfmt.yaml | 24 ------- .gitignore | 3 - .travis.yml | 34 ---------- .vscode/settings.json | 10 --- CODE_OF_CONDUCT.md | 37 ----------- CHANGELOG.md => e310x-hal/CHANGELOG.md | 0 Cargo.toml => e310x-hal/Cargo.toml | 0 README.md => e310x-hal/README.md | 0 {src => e310x-hal/src}/clock.rs | 0 {src => e310x-hal/src}/core/clint.rs | 0 {src => e310x-hal/src}/core/counters.rs | 0 {src => e310x-hal/src}/core/mod.rs | 0 {src => e310x-hal/src}/core/plic.rs | 0 {src => e310x-hal/src}/delay.rs | 0 {src => e310x-hal/src}/device.rs | 0 {src => e310x-hal/src}/gpio.rs | 0 {src => e310x-hal/src}/i2c.rs | 0 {src => e310x-hal/src}/interrupt.rs | 0 {src => e310x-hal/src}/lib.rs | 0 {src => e310x-hal/src}/pmu.rs | 0 {src => e310x-hal/src}/prelude.rs | 0 {src => e310x-hal/src}/pwm.rs | 0 {src => e310x-hal/src}/rtc.rs | 0 {src => e310x-hal/src}/serial.rs | 0 {src => e310x-hal/src}/spi.rs | 0 {src => e310x-hal/src}/spi/bus.rs | 0 {src => e310x-hal/src}/spi/config.rs | 0 .../src}/spi/exclusive_device.rs | 0 {src => e310x-hal/src}/spi/shared_bus.rs | 0 {src => e310x-hal/src}/spi/shared_device.rs | 0 {src => e310x-hal/src}/spi/traits.rs | 0 {src => e310x-hal/src}/stdout.rs | 0 {src => e310x-hal/src}/time.rs | 0 {src => e310x-hal/src}/wdog.rs | 0 37 files changed, 182 deletions(-) delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/bors.toml delete mode 100644 .github/workflows/ci.yaml delete mode 100644 .github/workflows/rustfmt.yaml delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 .vscode/settings.json delete mode 100644 CODE_OF_CONDUCT.md rename CHANGELOG.md => e310x-hal/CHANGELOG.md (100%) rename Cargo.toml => e310x-hal/Cargo.toml (100%) rename README.md => e310x-hal/README.md (100%) rename {src => e310x-hal/src}/clock.rs (100%) rename {src => e310x-hal/src}/core/clint.rs (100%) rename {src => e310x-hal/src}/core/counters.rs (100%) rename {src => e310x-hal/src}/core/mod.rs (100%) rename {src => e310x-hal/src}/core/plic.rs (100%) rename {src => e310x-hal/src}/delay.rs (100%) rename {src => e310x-hal/src}/device.rs (100%) rename {src => e310x-hal/src}/gpio.rs (100%) rename {src => e310x-hal/src}/i2c.rs (100%) rename {src => e310x-hal/src}/interrupt.rs (100%) rename {src => e310x-hal/src}/lib.rs (100%) rename {src => e310x-hal/src}/pmu.rs (100%) rename {src => e310x-hal/src}/prelude.rs (100%) rename {src => e310x-hal/src}/pwm.rs (100%) rename {src => e310x-hal/src}/rtc.rs (100%) rename {src => e310x-hal/src}/serial.rs (100%) rename {src => e310x-hal/src}/spi.rs (100%) rename {src => e310x-hal/src}/spi/bus.rs (100%) rename {src => e310x-hal/src}/spi/config.rs (100%) rename {src => e310x-hal/src}/spi/exclusive_device.rs (100%) rename {src => e310x-hal/src}/spi/shared_bus.rs (100%) rename {src => e310x-hal/src}/spi/shared_device.rs (100%) rename {src => e310x-hal/src}/spi/traits.rs (100%) rename {src => e310x-hal/src}/stdout.rs (100%) rename {src => e310x-hal/src}/time.rs (100%) rename {src => e310x-hal/src}/wdog.rs (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 87f6c03..0000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @rust-embedded/riscv \ No newline at end of file diff --git a/.github/bors.toml b/.github/bors.toml deleted file mode 100644 index b5b4935..0000000 --- a/.github/bors.toml +++ /dev/null @@ -1,10 +0,0 @@ -block_labels = ["needs-decision"] -delete_merged_branches = true -required_approvals = 1 -status = [ - "ci-linux (stable)", - "ci-linux (1.42.0)", - "build-other (macOS-latest)", - "build-other (windows-latest)", - "Rustfmt" -] diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 432c595..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,63 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Continuous integration - -jobs: - ci-linux: - runs-on: ubuntu-20.04 - continue-on-error: ${{ matrix.experimental || false }} - strategy: - matrix: - # All generated code should be running on stable now, MRSV is 1.60.0 - rust: [nightly, stable, 1.60.0] - - include: - # Nightly is only for reference and allowed to fail - - rust: nightly - experimental: true - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - override: true - - name: Install all Rust targets for ${{ matrix.rust }} - run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv32imc-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv32imac-unknown-none-elf - cargo check --target riscv32imac-unknown-none-elf --features g002 - cargo check --target riscv32imac-unknown-none-elf --features virq - cargo check --target riscv32imac-unknown-none-elf --features g002,virq - cargo check --target riscv32imc-unknown-none-elf - cargo check --target riscv32imc-unknown-none-elf --features g002 - cargo check --target riscv32imc-unknown-none-elf --features virq - cargo check --target riscv32imc-unknown-none-elf --features g002,virq - - # On macOS and Windows, we at least make sure that the crate builds and links. - build-other: - strategy: - matrix: - os: - - macOS-latest - - windows-latest - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - name: Build crate for host OS - run: | - cargo build - cargo build --features g002 - cargo build --features virq - cargo build --features g002,virq \ No newline at end of file diff --git a/.github/workflows/rustfmt.yaml b/.github/workflows/rustfmt.yaml deleted file mode 100644 index 0727384..0000000 --- a/.github/workflows/rustfmt.yaml +++ /dev/null @@ -1,24 +0,0 @@ - -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Code formatting check - -jobs: - fmt: - name: Rustfmt - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a9a12f2..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -Cargo.lock -target/ -.gdb_history \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index badfe86..0000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: rust - -env: -- TARGET=x86_64-unknown-linux-gnu -- TARGET=riscv32imac-unknown-none-elf - -rust: -- nightly -- stable - -if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - -install: - - ci/install.sh - -script: - - ci/script.sh - - -cache: cargo -before_cache: - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo - -branches: - only: - - master - - staging - - trying - -notifications: - email: - on_success: never diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 2781fab..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "[rust]": { - "editor.defaultFormatter": "rust-lang.rust-analyzer", - "editor.formatOnSave": true - }, - "rust-analyzer.cargo.features": [ - "g002", - "virq", - ] -} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index fccadf9..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,37 +0,0 @@ -# The Rust Code of Conduct - -## Conduct - -**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team) - -* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. -* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. -* Please be kind and courteous. There's no need to be mean or rude. -* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. -* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. -* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. -* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. -* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. - -## Moderation - -These are the policies for upholding our community's standards of conduct. - -1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) -2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. -3. Moderators will first respond to such remarks with a warning. -4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. -5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. -6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. -7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. -8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. - -In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. - -And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. - -The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). - -*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* - -[team]: https://github.com/rust-embedded/wg#the-riscv-team diff --git a/CHANGELOG.md b/e310x-hal/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to e310x-hal/CHANGELOG.md diff --git a/Cargo.toml b/e310x-hal/Cargo.toml similarity index 100% rename from Cargo.toml rename to e310x-hal/Cargo.toml diff --git a/README.md b/e310x-hal/README.md similarity index 100% rename from README.md rename to e310x-hal/README.md diff --git a/src/clock.rs b/e310x-hal/src/clock.rs similarity index 100% rename from src/clock.rs rename to e310x-hal/src/clock.rs diff --git a/src/core/clint.rs b/e310x-hal/src/core/clint.rs similarity index 100% rename from src/core/clint.rs rename to e310x-hal/src/core/clint.rs diff --git a/src/core/counters.rs b/e310x-hal/src/core/counters.rs similarity index 100% rename from src/core/counters.rs rename to e310x-hal/src/core/counters.rs diff --git a/src/core/mod.rs b/e310x-hal/src/core/mod.rs similarity index 100% rename from src/core/mod.rs rename to e310x-hal/src/core/mod.rs diff --git a/src/core/plic.rs b/e310x-hal/src/core/plic.rs similarity index 100% rename from src/core/plic.rs rename to e310x-hal/src/core/plic.rs diff --git a/src/delay.rs b/e310x-hal/src/delay.rs similarity index 100% rename from src/delay.rs rename to e310x-hal/src/delay.rs diff --git a/src/device.rs b/e310x-hal/src/device.rs similarity index 100% rename from src/device.rs rename to e310x-hal/src/device.rs diff --git a/src/gpio.rs b/e310x-hal/src/gpio.rs similarity index 100% rename from src/gpio.rs rename to e310x-hal/src/gpio.rs diff --git a/src/i2c.rs b/e310x-hal/src/i2c.rs similarity index 100% rename from src/i2c.rs rename to e310x-hal/src/i2c.rs diff --git a/src/interrupt.rs b/e310x-hal/src/interrupt.rs similarity index 100% rename from src/interrupt.rs rename to e310x-hal/src/interrupt.rs diff --git a/src/lib.rs b/e310x-hal/src/lib.rs similarity index 100% rename from src/lib.rs rename to e310x-hal/src/lib.rs diff --git a/src/pmu.rs b/e310x-hal/src/pmu.rs similarity index 100% rename from src/pmu.rs rename to e310x-hal/src/pmu.rs diff --git a/src/prelude.rs b/e310x-hal/src/prelude.rs similarity index 100% rename from src/prelude.rs rename to e310x-hal/src/prelude.rs diff --git a/src/pwm.rs b/e310x-hal/src/pwm.rs similarity index 100% rename from src/pwm.rs rename to e310x-hal/src/pwm.rs diff --git a/src/rtc.rs b/e310x-hal/src/rtc.rs similarity index 100% rename from src/rtc.rs rename to e310x-hal/src/rtc.rs diff --git a/src/serial.rs b/e310x-hal/src/serial.rs similarity index 100% rename from src/serial.rs rename to e310x-hal/src/serial.rs diff --git a/src/spi.rs b/e310x-hal/src/spi.rs similarity index 100% rename from src/spi.rs rename to e310x-hal/src/spi.rs diff --git a/src/spi/bus.rs b/e310x-hal/src/spi/bus.rs similarity index 100% rename from src/spi/bus.rs rename to e310x-hal/src/spi/bus.rs diff --git a/src/spi/config.rs b/e310x-hal/src/spi/config.rs similarity index 100% rename from src/spi/config.rs rename to e310x-hal/src/spi/config.rs diff --git a/src/spi/exclusive_device.rs b/e310x-hal/src/spi/exclusive_device.rs similarity index 100% rename from src/spi/exclusive_device.rs rename to e310x-hal/src/spi/exclusive_device.rs diff --git a/src/spi/shared_bus.rs b/e310x-hal/src/spi/shared_bus.rs similarity index 100% rename from src/spi/shared_bus.rs rename to e310x-hal/src/spi/shared_bus.rs diff --git a/src/spi/shared_device.rs b/e310x-hal/src/spi/shared_device.rs similarity index 100% rename from src/spi/shared_device.rs rename to e310x-hal/src/spi/shared_device.rs diff --git a/src/spi/traits.rs b/e310x-hal/src/spi/traits.rs similarity index 100% rename from src/spi/traits.rs rename to e310x-hal/src/spi/traits.rs diff --git a/src/stdout.rs b/e310x-hal/src/stdout.rs similarity index 100% rename from src/stdout.rs rename to e310x-hal/src/stdout.rs diff --git a/src/time.rs b/e310x-hal/src/time.rs similarity index 100% rename from src/time.rs rename to e310x-hal/src/time.rs diff --git a/src/wdog.rs b/e310x-hal/src/wdog.rs similarity index 100% rename from src/wdog.rs rename to e310x-hal/src/wdog.rs From 829ea571eb924b085e2553be201c264fc44a2726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Sat, 21 Sep 2024 19:15:05 +0200 Subject: [PATCH 311/315] Adapt e310x-hal to new version of e310x --- .github/workflows/changelog.yaml | 11 +++++ .github/workflows/e310x-hal.yaml | 51 +++++++++++++++++++ .gitignore | 3 +- .travis.yml | 33 ------------- Cargo.toml | 1 + README.md | 1 + e310x-hal/CHANGELOG.md | 3 ++ e310x-hal/Cargo.toml | 8 +-- e310x-hal/src/clock.rs | 54 ++++++++++---------- e310x-hal/src/core/clint.rs | 18 +++---- e310x-hal/src/core/mod.rs | 4 +- e310x-hal/src/core/plic.rs | 40 ++++++++------- e310x-hal/src/device.rs | 77 ++++++++++++++--------------- e310x-hal/src/gpio.rs | 28 +++++------ e310x-hal/src/i2c.rs | 26 +++++----- e310x-hal/src/interrupt.rs | 2 +- e310x-hal/src/pmu.rs | 51 ++++++++++--------- e310x-hal/src/pwm.rs | 74 ++++++++++++++-------------- e310x-hal/src/rtc.rs | 28 ++++++----- e310x-hal/src/serial.rs | 54 ++++++++++---------- e310x-hal/src/spi.rs | 6 ++- e310x-hal/src/spi/bus.rs | 58 +++++++++++----------- e310x-hal/src/spi/config.rs | 4 +- e310x-hal/src/spi/shared_bus.rs | 1 - e310x-hal/src/spi/traits.rs | 84 ++++++++++++++++---------------- e310x-hal/src/wdog.rs | 17 ++++--- e310x/CHANGELOG.md | 2 +- e310x/Cargo.toml | 2 +- 28 files changed, 397 insertions(+), 344 deletions(-) create mode 100644 .github/workflows/e310x-hal.yaml delete mode 100644 .travis.yml diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index ddc52ad..61dcc37 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -19,6 +19,8 @@ jobs: filters: | e310x: - 'e310x/**' + e310x-hal: + - 'e310x-hal/**' - name: Check for CHANGELOG.md (e310x) if: steps.changes.outputs['e310x'] == 'true' @@ -27,3 +29,12 @@ jobs: changeLogPath: ./e310x/CHANGELOG.md skipLabels: 'skip changelog' missingUpdateErrorMessage: 'Please add a changelog entry in the e310x/CHANGELOG.md file.' + + - name: Check for CHANGELOG.md (e310x-hal) + if: steps.changes.outputs['e310x-hal'] == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: ./e310x-hal/CHANGELOG.md + skipLabels: 'skip changelog' + missingUpdateErrorMessage: 'Please add a changelog entry in the e310x-hal/CHANGELOG.md file.' + \ No newline at end of file diff --git a/.github/workflows/e310x-hal.yaml b/.github/workflows/e310x-hal.yaml new file mode 100644 index 0000000..043e24d --- /dev/null +++ b/.github/workflows/e310x-hal.yaml @@ -0,0 +1,51 @@ +on: + push: + branches: [ master ] + pull_request: + merge_group: + +name: Build check (e310x-hal) + +jobs: + # We check that the crate builds and links for all the toolchains and targets. + build-riscv: + strategy: + matrix: + # All generated code should be running on stable now, MRSV is 1.65.0 + toolchain: [ stable, nightly, 1.65.0 ] + target: + - riscv32imc-unknown-none-elf + - riscv32imac-unknown-none-elf # TODO e310x is not a purely IMAC core + include: + # Nightly is only for reference and allowed to fail + - toolchain: nightly + experimental: true + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || false }} + steps: + - uses: actions/checkout@v4 + - name: Update Rust toolchain + run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - name: Install Rust target + run: rustup target install ${{ matrix.target }} + - name: Build (no features) + run: cargo build --package e310x-hal --target ${{ matrix.target }} + - name: Build (all features) + run: cargo build --package e310x-hal --target ${{ matrix.target }} --all-features + + # On MacOS and Ubuntu, we at least make sure that the crate builds and links. + # On Windows, linking fails when the rt feature is enabled. + build-others: + strategy: + matrix: + os: [ macos-latest, ubuntu-latest ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Update Rust toolchain + run: rustup update stable && rustup default stable + - name: Build (no features) + run: cargo test --package e310x-hal + - name: Build (all features) + run: cargo test --package e310x-hal --all-features + \ No newline at end of file diff --git a/.gitignore b/.gitignore index b354aec..9182e2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ Cargo.lock -target/ \ No newline at end of file +target/ +.vscode/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5dc69be..0000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -language: rust - -env: - - TARGET=x86_64-unknown-linux-gnu - - TARGET=riscv32imac-unknown-none-elf - -rust: - - nightly - - stable - -if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - -install: - - ci/install.sh - -script: - - ci/script.sh - -cache: cargo -before_cache: - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo - -branches: - only: - - master - - staging - - trying - -notifications: - email: - on_success: never diff --git a/Cargo.toml b/Cargo.toml index 0a4be38..b29765b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,5 @@ resolver = "2" members = [ "e310x", + "e310x-hal", ] diff --git a/README.md b/README.md index d6ff951..4532724 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ This repository contains various crates useful for writing Rust programs on E310x microcontrollers: * [`e310x`]: Peripheral Access Crate (PAC) for E310x chips. +* [`e310x-hal`]: HAL for the E310x family of microcontrollers. This project is developed and maintained by the [RISC-V team][team]. diff --git a/e310x-hal/CHANGELOG.md b/e310x-hal/CHANGELOG.md index aa47fb6..d2e709d 100644 --- a/e310x-hal/CHANGELOG.md +++ b/e310x-hal/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- Update `e310x` dependency and adapt code +- Bump MSRV to 1.65.0 (check Cargo.toml) - Use `portable-atomic` to allow builds on `riscv32imc-unknown-none-elf`` targets when needed. ## [v0.10.0] - 2023-03-28 diff --git a/e310x-hal/Cargo.toml b/e310x-hal/Cargo.toml index ca7141c..052429d 100644 --- a/e310x-hal/Cargo.toml +++ b/e310x-hal/Cargo.toml @@ -2,19 +2,19 @@ name = "e310x-hal" version = "0.11.0" authors = ["David Craven "] -repository = "https://github.com/riscv-rust/e310x-hal" +repository = "https://github.com/riscv-rust/e310x" categories = ["embedded", "hardware-support", "no-std"] description = "HAL for the E310x family of microcontrollers." keywords = ["riscv", "e310", "hal"] license = "ISC" -edition = "2018" -rust-version = "1.59" +edition = "2021" +rust-version = "1.65" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } -e310x = { version = "0.11.0", features = ["rt", "critical-section"] } +e310x = { path = "../e310x", version = "0.11.0", features = ["rt", "critical-section"] } [target.'cfg(not(target_has_atomic = "32"))'.dependencies] portable-atomic = { version = "1.4", default-features = false, features = ["unsafe-assume-single-core"] } diff --git a/e310x-hal/src/clock.rs b/e310x-hal/src/clock.rs index b011cdd..29c359d 100644 --- a/e310x-hal/src/clock.rs +++ b/e310x-hal/src/clock.rs @@ -1,7 +1,7 @@ //! Clock configuration use crate::core::clint::MTIME; use crate::time::Hertz; -use e310x::{AONCLK, PRCI}; +use e310x::{Aonclk as AONCLK, Prci as PRCI}; use riscv::interrupt; use riscv::register::mcycle; @@ -72,10 +72,10 @@ impl CoreClk { // Assume `psdclkbypass_n` is not used // Temporarily switch to the internal oscillator - let prci = unsafe { &*PRCI::ptr() }; + let prci = unsafe { PRCI::steal() }; let hfrosc_freq = self.configure_hfrosc(); // Switch to HFROSC, bypass PLL - prci.pllcfg + prci.pllcfg() .modify(|_, w| w.sel().bit(false).bypass().bit(true)); if let Some(freq) = self.hfxosc { @@ -87,16 +87,16 @@ impl CoreClk { /// Configures clock generation system with external oscillator fn configure_with_external(self, source_freq: Hertz) -> Hertz { - let prci = unsafe { &*PRCI::ptr() }; + let prci = unsafe { PRCI::steal() }; // Enable HFXOSC - prci.hfxosccfg.write(|w| w.enable().bit(true)); + prci.hfxosccfg().write(|w| w.enable().bit(true)); // Wait for HFXOSC to stabilize - while !prci.hfxosccfg.read().ready().bit_is_set() {} + while !prci.hfxosccfg().read().ready().bit_is_set() {} // Select HFXOSC as pllref - prci.pllcfg.modify(|_, w| w.refsel().bit(true)); + prci.pllcfg().modify(|_, w| w.refsel().bit(true)); let freq; if source_freq.0 == self.coreclk.0 { @@ -104,10 +104,10 @@ impl CoreClk { freq = source_freq; // Bypass PLL - prci.pllcfg.modify(|_, w| w.bypass().bit(true)); + prci.pllcfg().modify(|_, w| w.bypass().bit(true)); // Bypass divider - prci.plloutdiv.write(|w| w.divby1().bit(true)); + prci.plloutdiv().write(|w| w.divby1().bit(true)); } else { // Use external oscillator with PLL @@ -116,17 +116,17 @@ impl CoreClk { } // Switch to PLL - prci.pllcfg.modify(|_, w| w.sel().bit(true)); + prci.pllcfg().modify(|_, w| w.sel().bit(true)); // Disable HFROSC to save power - prci.hfrosccfg.write(|w| w.enable().bit(false)); + prci.hfrosccfg().write(|w| w.enable().bit(false)); freq } /// Configures clock generation system with internal oscillator fn configure_with_internal(self, hfrosc_freq: Hertz) -> Hertz { - let prci = unsafe { &*PRCI::ptr() }; + let prci = unsafe { PRCI::steal() }; let freq; if hfrosc_freq.0 == self.coreclk.0 { @@ -134,11 +134,11 @@ impl CoreClk { freq = hfrosc_freq; // Switch to HFROSC, bypass PLL to save power - prci.pllcfg + prci.pllcfg() .modify(|_, w| w.sel().bit(false).bypass().bit(true)); // - prci.pllcfg.modify(|_, w| w.bypass().bit(true)); + prci.pllcfg().modify(|_, w| w.bypass().bit(true)); } else { // Use internal oscillator with PLL @@ -146,27 +146,27 @@ impl CoreClk { freq = self.configure_pll(hfrosc_freq, self.coreclk); // Switch to PLL - prci.pllcfg.modify(|_, w| w.sel().bit(true)); + prci.pllcfg().modify(|_, w| w.sel().bit(true)); } // Disable HFXOSC to save power - prci.hfxosccfg.write(|w| w.enable().bit(false)); + prci.hfxosccfg().write(|w| w.enable().bit(false)); freq } /// Configures internal high-frequency oscillator (`HFROSC`) fn configure_hfrosc(&self) -> Hertz { - let prci = unsafe { &*PRCI::ptr() }; + let prci = unsafe { PRCI::steal() }; // TODO: use trim value from OTP // Configure HFROSC to 13.8 MHz - prci.hfrosccfg + prci.hfrosccfg() .write(|w| unsafe { w.div().bits(4).trim().bits(16).enable().bit(true) }); // Wait for HFROSC to stabilize - while !prci.hfrosccfg.read().ready().bit_is_set() {} + while !prci.hfrosccfg().read().ready().bit_is_set() {} Hertz(13_800_000) } @@ -270,8 +270,8 @@ impl CoreClk { }; // Configure PLL - let prci = unsafe { &*PRCI::ptr() }; - prci.pllcfg.modify(|_, w| unsafe { + let prci = unsafe { PRCI::steal() }; + prci.pllcfg().modify(|_, w| unsafe { w.pllr() .bits(r) .pllf() @@ -283,7 +283,7 @@ impl CoreClk { }); // Configure PLL Output Divider - prci.plloutdiv + prci.plloutdiv() .write(|w| unsafe { w.div().bits(divider_div as u8).divby1().bit(divider_bypass) }); // Wait for PLL Lock @@ -295,7 +295,7 @@ impl CoreClk { let time = mtime.mtime() + 4; while mtime.mtime() < time {} // Now it is safe to check for PLL Lock - while !prci.pllcfg.read().lock().bit_is_set() {} + while !prci.pllcfg().read().lock().bit_is_set() {} Hertz(divout_freq) } @@ -318,13 +318,13 @@ impl AonClk { /// Freezes low-frequency clock configuration, making it effective pub(crate) fn freeze(self) -> Hertz { - let aonclk = unsafe { &*AONCLK::ptr() }; + let aonclk = unsafe { AONCLK::steal() }; if let Some(freq) = self.lfaltclk { // Use external oscillator. // Disable unused LFROSC to save power. - aonclk.lfrosccfg.write(|w| w.enable().bit(false)); + aonclk.lfrosccfg().write(|w| w.enable().bit(false)); freq } else { @@ -334,14 +334,14 @@ impl AonClk { let div = 4; // LFROSC/5 // Configure LFROSC - aonclk.lfrosccfg.write(|w| unsafe { + aonclk.lfrosccfg().write(|w| unsafe { w.trim().bits(trim); w.div().bits(div); w.enable().bit(true) }); // Wait for LFROSC to stabilize - while !aonclk.lfrosccfg.read().ready().bit_is_set() {} + while !aonclk.lfrosccfg().read().ready().bit_is_set() {} Hertz(32_768) // It's not so accurate: ≈30 kHz according to the datasheet } diff --git a/e310x-hal/src/core/clint.rs b/e310x-hal/src/core/clint.rs index 0788979..82912e6 100644 --- a/e310x-hal/src/core/clint.rs +++ b/e310x-hal/src/core/clint.rs @@ -1,6 +1,6 @@ //! Core-Local Interruptor -use e310x::CLINT; +use e310x::Clint as CLINT; macro_rules! read64 { ($hi:expr, $lo:expr) => { @@ -23,8 +23,8 @@ impl MSIP { /// Set msip register value pub fn set_value(&mut self, value: bool) { unsafe { - (*CLINT::ptr()) - .msip + CLINT::steal() + .msip() .write(|w| if value { w.bits(1) } else { w.bits(0) }) } } @@ -37,13 +37,13 @@ impl MTIME { /// Read mtime register. #[inline] pub fn mtime_lo(&self) -> u32 { - unsafe { (*CLINT::ptr()).mtime.read().bits() } + unsafe { CLINT::steal() }.mtime().read().bits() } /// Read mtimeh register. #[inline] pub fn mtime_hi(&self) -> u32 { - unsafe { (*CLINT::ptr()).mtimeh.read().bits() } + unsafe { CLINT::steal() }.mtimeh().read().bits() } /// Read mtime and mtimeh registers. @@ -61,13 +61,13 @@ impl MTIMECMP { /// Read mtimecmp register. #[inline] pub fn mtimecmp_lo(&self) -> u32 { - unsafe { (*CLINT::ptr()).mtimecmp.read().bits() } + unsafe { CLINT::steal() }.mtimecmp().read().bits() } /// Read mtimecmph register. #[inline] pub fn mtimecmp_hi(&self) -> u32 { - unsafe { (*CLINT::ptr()).mtimecmph.read().bits() } + unsafe { CLINT::steal() }.mtimecmph().read().bits() } /// Read mtimecmp and mtimecmph registers. @@ -78,13 +78,13 @@ impl MTIMECMP { /// Write mtimecmp register #[inline] pub fn set_mtimecmp_lo(&mut self, value: u32) { - unsafe { (*CLINT::ptr()).mtimecmp.write(|w| w.bits(value)) }; + unsafe { CLINT::steal().mtimecmp().write(|w| w.bits(value)) }; } /// Write mtimecmph register #[inline] pub fn set_mtimecmp_hi(&mut self, value: u32) { - unsafe { (*CLINT::ptr()).mtimecmph.write(|w| w.bits(value)) }; + unsafe { CLINT::steal().mtimecmph().write(|w| w.bits(value)) }; } /// Write mtimecmp and mtimecmph registers. diff --git a/e310x-hal/src/core/mod.rs b/e310x-hal/src/core/mod.rs index c1bd189..43d1483 100644 --- a/e310x-hal/src/core/mod.rs +++ b/e310x-hal/src/core/mod.rs @@ -17,7 +17,7 @@ pub struct CorePeripherals { } impl CorePeripherals { - pub(crate) fn new(clint: e310x::CLINT, plic: e310x::PLIC) -> Self { + pub(crate) fn new(clint: e310x::Clint, plic: e310x::Plic) -> Self { Self { clint: clint.into(), plic: plic.into(), @@ -28,6 +28,6 @@ impl CorePeripherals { /// Steal the peripherals pub unsafe fn steal() -> Self { let p = e310x::Peripherals::steal(); - Self::new(p.CLINT, p.PLIC) + Self::new(p.clint, p.plic) } } diff --git a/e310x-hal/src/core/plic.rs b/e310x-hal/src/core/plic.rs index 2130afa..3da4167 100644 --- a/e310x-hal/src/core/plic.rs +++ b/e310x-hal/src/core/plic.rs @@ -1,7 +1,7 @@ //! Platform-Level Interrupt Controller use core::marker::PhantomData; use e310x::Interrupt; -use e310x::PLIC; +use e310x::Plic as PLIC; use riscv::register::{mie, mip}; /// Priority of a plic::Interrupt. @@ -145,7 +145,7 @@ impl THRESHOLD { /// Returns the current active priority threshold. pub fn get(&self) -> Priority { // NOTE: Atomic read with no side effects. - let threshold = unsafe { (*PLIC::ptr()).threshold.read() }; + let threshold = unsafe { PLIC::steal() }.threshold().read(); Priority::from(threshold.bits()).unwrap() } @@ -153,9 +153,7 @@ impl THRESHOLD { /// deactivates all interrupts with a lower priority. pub fn set(&mut self, priority: Priority) { // NOTE: Atomic write with no side effects. - unsafe { - (*PLIC::ptr()).threshold.write(|w| w.bits(priority.into())); - } + unsafe { PLIC::steal().threshold().write(|w| w.bits(priority.into())) }; } } @@ -168,7 +166,7 @@ impl CLAIM { /// Claims the interrupt with the highest priority. pub fn claim(&mut self) -> Option { // NOTE: Atomic read with side effects. - let intr = unsafe { (*PLIC::ptr()).claim.read().bits() }; + let intr = unsafe { PLIC::steal() }.claim().read().bits(); // If no interrupt is pending return None if intr == 0 { @@ -181,9 +179,7 @@ impl CLAIM { /// Notifies the PLIC that a claimed interrupt is complete. pub fn complete(&mut self, intr: Interrupt) { // NOTE: Atomic write with side effects. - unsafe { - (*PLIC::ptr()).claim.write(|w| w.bits(intr as u32)); - } + unsafe { PLIC::steal().claim().write(|w| w.bits(intr as u32)) }; } } @@ -204,8 +200,10 @@ impl INTERRUPT { pub fn enable(&mut self) { // NOTE: should use atomic operations unsafe { - (*PLIC::ptr()).enable[self.offset].modify(|r, w| w.bits(r.bits() | self.mask)); - } + PLIC::steal() + .enable(self.offset) + .modify(|r, w| w.bits(r.bits() | self.mask)) + }; } /// Disable IRQ interrupt. @@ -213,28 +211,32 @@ impl INTERRUPT { pub fn disable(&mut self) { // NOTE: should use atomic operations unsafe { - (*PLIC::ptr()).enable[self.offset].modify(|r, w| w.bits(r.bits() & !self.mask)); - } + PLIC::steal() + .enable(self.offset) + .modify(|r, w| w.bits(r.bits() & !self.mask)) + }; } /// Returns true when IRQ interrupt is pending. pub fn is_pending(&self) -> bool { // NOTE: Atomic write without side effects. - let pending = unsafe { (*PLIC::ptr()).pending[self.offset].read() }; + let pending = unsafe { PLIC::steal() }.pending(self.offset).read(); pending.bits() & self.mask == self.mask } /// Returns true when WDOG interrupt is enabled. pub fn is_enabled(&self) -> bool { // NOTE: Atomic write without side effects. - let enabled = unsafe { (*PLIC::ptr()).enable[self.offset].read() }; + let enabled = unsafe { PLIC::steal() }.enable(self.offset).read(); enabled.bits() & self.mask == self.mask } /// Returns the priority of the IRQ interrupt. pub fn priority(&self) -> Priority { // NOTE: Atomic read without side effects. - let priority = unsafe { (*PLIC::ptr()).priority[self.priority_offset].read() }; + let priority = unsafe { PLIC::steal() } + .priority(self.priority_offset) + .read(); Priority::from(priority.bits()).unwrap() } @@ -242,7 +244,9 @@ impl INTERRUPT { pub fn set_priority(&mut self, priority: Priority) { // NOTE: Atomic write without side effects. unsafe { - (*PLIC::ptr()).priority[self.priority_offset].write(|w| w.bits(priority as u32)); - } + PLIC::steal() + .priority(self.priority_offset) + .write(|w| w.bits(priority as u32)) + }; } } diff --git a/e310x-hal/src/device.rs b/e310x-hal/src/device.rs index a95d4cf..f1a2f13 100644 --- a/e310x-hal/src/device.rs +++ b/e310x-hal/src/device.rs @@ -3,51 +3,51 @@ use crate::core::CorePeripherals; use crate::gpio::{gpio0::*, GpioExt, Unknown}; use e310x::{ - Peripherals, AONCLK, BACKUP, GPIO0, OTP, PMU, PRCI, PWM0, PWM1, PWM2, QSPI0, QSPI1, RTC, UART0, - WDOG, + Aonclk, Backup, Gpio0, Otp, Peripherals, Pmu, Prci, Pwm0, Pwm1, Pwm2, Qspi0, Qspi1, Rtc, Uart0, + Wdog, }; #[cfg(feature = "g002")] -use e310x::{I2C0, UART1}; +use e310x::{I2c0, Uart1}; /// Device peripherals available in a 48QFN package, except GPIO0 #[allow(non_snake_case)] pub struct DevicePeripherals { /// WDOG peripheral - pub WDOG: WDOG, + pub WDOG: Wdog, /// RTC peripheral - pub RTC: RTC, + pub RTC: Rtc, /// AONCLK peripheral - pub AONCLK: AONCLK, + pub AONCLK: Aonclk, /// BACKUP peripheral - pub BACKUP: BACKUP, + pub BACKUP: Backup, /// PMU peripheral - pub PMU: PMU, + pub PMU: Pmu, /// PRCI peripheral - pub PRCI: PRCI, + pub PRCI: Prci, /// OTP peripheral - pub OTP: OTP, + pub OTP: Otp, /// UART0 peripheral - pub UART0: UART0, + pub UART0: Uart0, #[cfg(feature = "g002")] /// UART1 peripheral (FE310-G002 only) - pub UART1: UART1, + pub UART1: Uart1, /// QSPI0 peripheral - pub QSPI0: QSPI0, + pub QSPI0: Qspi0, /// QSPI1 peripheral - pub QSPI1: QSPI1, + pub QSPI1: Qspi1, #[cfg(feature = "g002")] /// I2C0 peripheral (FE310-G002 only) - pub I2C0: I2C0, + pub I2C0: I2c0, /// PWM0 peripheral - pub PWM0: PWM0, + pub PWM0: Pwm0, /// PWM1 peripheral - pub PWM1: PWM1, + pub PWM1: Pwm1, /// PWM2 peripheral - pub PWM2: PWM2, + pub PWM2: Pwm2, } /// Device GPIO pins available in a 48QFN package @@ -92,9 +92,10 @@ pub struct DeviceGpioPins { pub pin23: Pin23, } -impl From for DeviceGpioPins { - fn from(gpio: GPIO0) -> Self { +impl From for DeviceGpioPins { + fn from(gpio: Gpio0) -> Self { let parts = gpio.split(); + DeviceGpioPins { pin0: parts.pin0, pin1: parts.pin1, @@ -134,33 +135,33 @@ pub struct DeviceResources { impl From for DeviceResources { fn from(p: Peripherals) -> Self { let peripherals = DevicePeripherals { - WDOG: p.WDOG, - RTC: p.RTC, - AONCLK: p.AONCLK, - BACKUP: p.BACKUP, - PMU: p.PMU, - PRCI: p.PRCI, - OTP: p.OTP, - - UART0: p.UART0, + WDOG: p.wdog, + RTC: p.rtc, + AONCLK: p.aonclk, + BACKUP: p.backup, + PMU: p.pmu, + PRCI: p.prci, + OTP: p.otp, + + UART0: p.uart0, #[cfg(feature = "g002")] - UART1: p.UART1, + UART1: p.uart1, - QSPI0: p.QSPI0, - QSPI1: p.QSPI1, + QSPI0: p.qspi0, + QSPI1: p.qspi1, #[cfg(feature = "g002")] - I2C0: p.I2C0, + I2C0: p.i2c0, - PWM0: p.PWM0, - PWM1: p.PWM1, - PWM2: p.PWM2, + PWM0: p.pwm0, + PWM1: p.pwm1, + PWM2: p.pwm2, }; DeviceResources { - core_peripherals: CorePeripherals::new(p.CLINT, p.PLIC), + core_peripherals: CorePeripherals::new(p.clint, p.plic), peripherals, - pins: p.GPIO0.into(), + pins: p.gpio0.into(), } } } diff --git a/e310x-hal/src/gpio.rs b/e310x-hal/src/gpio.rs index 1061884..fb6d289 100644 --- a/e310x-hal/src/gpio.rs +++ b/e310x-hal/src/gpio.rs @@ -74,65 +74,65 @@ fn atomic_set_bit(r: &AtomicU32, index: usize, bit: bool) { } trait PeripheralAccess { - fn peripheral() -> &'static e310x::gpio0::RegisterBlock; + fn peripheral() -> e310x::Gpio0; fn input_value(index: usize) -> bool { let p = Self::peripheral(); - (p.input_val.read().bits() >> (index & 31) & 1) != 0 + (p.input_val().read().bits() >> (index & 31) & 1) != 0 } 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 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); } } @@ -162,8 +162,8 @@ macro_rules! gpio { impl PeripheralAccess for $GPIOX { #[inline(always)] - fn peripheral() -> &'static e310x::gpio0::RegisterBlock { - unsafe { &*$GPIOX::ptr() } + fn peripheral() -> e310x::Gpio0 { + unsafe { $GPIOX::steal() } } } @@ -333,7 +333,7 @@ macro_rules! gpio { // By default, all GPIOs are in the Unknown state for two reasons: // * bootloader may reconfigure some GPIOs // * we do not enforce any specific state in `split()` -gpio!(GPIO0, gpio0, [ +gpio!(Gpio0, gpio0, [ Pin0: (pin0, 0, Unknown), Pin1: (pin1, 1, Unknown), Pin2: (pin2, 2, Unknown), diff --git a/e310x-hal/src/i2c.rs b/e310x-hal/src/i2c.rs index d969add..c0aac2d 100644 --- a/e310x-hal/src/i2c.rs +++ b/e310x-hal/src/i2c.rs @@ -15,7 +15,7 @@ use crate::gpio::{gpio0, IOF0}; use crate::time::Bps; use core::mem; use core::ops::Deref; -use e310x::{i2c0, I2C0}; +use e310x::{i2c0, I2c0}; use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; /// SDA pin - DO NOT IMPLEMENT THIS TRAIT @@ -23,8 +23,8 @@ pub unsafe trait SdaPin {} /// SCL pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait SclPin {} -unsafe impl SdaPin for gpio0::Pin12> {} -unsafe impl SclPin for gpio0::Pin13> {} +unsafe impl SdaPin for gpio0::Pin12> {} +unsafe impl SclPin for gpio0::Pin13> {} /// I2C error #[derive(Debug, Eq, PartialEq)] @@ -57,12 +57,12 @@ pub struct I2c { pins: PINS, } -impl I2c { +impl I2c { /// Configures an I2C peripheral - pub fn new(i2c: I2C0, sda: SDA, scl: SCL, speed: Speed, clocks: Clocks) -> Self + pub fn new(i2c: I2c0, sda: SDA, scl: SCL, speed: Speed, clocks: Clocks) -> Self where - SDA: SdaPin, - SCL: SclPin, + SDA: SdaPin, + SCL: SclPin, { // Calculate prescaler value let desired_speed = match speed { @@ -76,18 +76,18 @@ impl I2c { assert!(prescaler < (1 << 16)); // Turn off i2c - i2c.ctr.write(|w| w.en().clear_bit().ien().clear_bit()); + i2c.ctr().write(|w| w.en().clear_bit().ien().clear_bit()); // Set prescaler let prescaler_lo = (prescaler & 0xff) as u8; let prescaler_hi = ((prescaler >> 8) & 0xff) as u8; - i2c.prer_lo + i2c.prer_lo() .write(|w| unsafe { w.value().bits(prescaler_lo) }); - i2c.prer_hi + i2c.prer_hi() .write(|w| unsafe { w.value().bits(prescaler_hi) }); // Turn on i2c - i2c.ctr.write(|w| w.en().set_bit()); + i2c.ctr().write(|w| w.en().set_bit()); Self { i2c, @@ -125,11 +125,11 @@ impl, PINS> I2c { } fn write_byte(&self, byte: u8) { - self.i2c.txr_rxr.write(|w| unsafe { w.data().bits(byte) }); + self.i2c.txr_rxr().write(|w| unsafe { w.data().bits(byte) }); } fn read_byte(&self) -> u8 { - self.i2c.txr_rxr.read().data().bits() + self.i2c.txr_rxr().read().data().bits() } fn wait_for_interrupt(&self) -> Result<(), Error> { diff --git a/e310x-hal/src/interrupt.rs b/e310x-hal/src/interrupt.rs index 45f2c4e..8599835 100644 --- a/e310x-hal/src/interrupt.rs +++ b/e310x-hal/src/interrupt.rs @@ -5,7 +5,7 @@ //! - You must activate the `virq` feature to use this module. //! //! - The vectored handler automatically claims the PLIC interrupt source as complete. -//! Thus, users do not have to worry about this step. +//! Thus, users do not have to worry about this step. //! //! # Features //! diff --git a/e310x-hal/src/pmu.rs b/e310x-hal/src/pmu.rs index 075e92d..21bb422 100644 --- a/e310x-hal/src/pmu.rs +++ b/e310x-hal/src/pmu.rs @@ -1,10 +1,12 @@ //! PMU Extension #![allow(missing_docs)] -use e310x::{BACKUP, PMU, RTC}; +use e310x::{Backup, Pmu, Rtc}; /// Backup register size in bytes const BACKUP_REGISTER_BYTES: usize = 4; +const BACKUP_LEN: usize = 16; + /// value required written to pmukey register before writing to other PMU registers pub const PMU_KEY_VAL: u32 = 0x51F15E; @@ -189,42 +191,43 @@ pub trait PMUExt { fn clear_backup(&self); } -impl PMUExt for PMU { +impl PMUExt for Pmu { fn load_default_programs(&self) { unsafe { for i in 0..8 { - self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); - self.pmusleeppm[i].write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); + self.pmukey().write(|w| w.bits(PMU_KEY_VAL)); + self.pmusleeppm(i) + .write(|w| w.bits(DEFAULT_SLEEP_PROGRAM[i])); - self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); - self.pmuwakepm[i].write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); + self.pmukey().write(|w| w.bits(PMU_KEY_VAL)); + self.pmuwakepm(i).write(|w| w.bits(DEFAULT_WAKE_PROGRAM[i])); } } } fn sleep(self, sleep_time: u32) { unsafe { - let rtc = RTC::ptr(); + let rtc = Rtc::steal(); // set interrupt source to RTC enabled, each pmu register needs key set before write - self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); - self.pmuie.write(|w| w.rtc().set_bit().dwakeup().set_bit()); + self.pmukey().write(|w| w.bits(PMU_KEY_VAL)); + self.pmuie() + .write(|w| w.rtc().set_bit().dwakeup().set_bit()); // set RTC clock scale to once per second for easy calculation - (*rtc) - .rtccfg + rtc.rtccfg() .write(|w| w.enalways().set_bit().scale().bits(15)); // get current RTC clock value scaled - let rtc_now = (*rtc).rtcs.read().bits(); + let rtc_now = rtc.rtcs().read().bits(); // set RTC clock comparator - (*rtc).rtccmp.write(|w| w.bits(rtc_now + sleep_time)); + rtc.rtccmp().write(|w| w.bits(rtc_now + sleep_time)); // go to sleep for sleep_time seconds, need to set pmukey here as well - self.pmukey.write(|w| w.bits(PMU_KEY_VAL)); - self.pmusleep.write(|w| w.sleep().set_bit()); + self.pmukey().write(|w| w.bits(PMU_KEY_VAL)); + self.pmusleep().write(|w| w.sleep().set_bit()); } } fn wakeup_cause(&self) -> Result { - let pmu_cause = self.pmucause.read(); + let pmu_cause = self.pmucause().read(); let wakeup_cause = pmu_cause.wakeupcause(); if wakeup_cause.is_rtc() { return Ok(WakeupCause::RTC); @@ -249,10 +252,10 @@ impl PMUExt for PMU { where UD: Sized, { - let backup = BACKUP::ptr(); + let backup = Backup::steal(); let ud_size = core::mem::size_of::(); - if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { + if ud_size > BACKUP_LEN * BACKUP_REGISTER_BYTES { return Err(BackupError::DataTooLarge); } @@ -267,7 +270,7 @@ impl PMUExt for PMU { let sliced = core::slice::from_raw_parts(ptr_u32, reg_count); for i in 0..sliced.len() { - (*backup).backup[i].write(|w| w.bits(sliced[i])); + backup.backup(i).write(|w| w.bits(sliced[i])); } Ok(()) @@ -277,10 +280,10 @@ impl PMUExt for PMU { where UD: Sized, { - let backup = BACKUP::ptr(); + let backup = Backup::steal(); let ud_size = core::mem::size_of::(); - if ud_size > (*backup).backup.len() * BACKUP_REGISTER_BYTES { + if ud_size > BACKUP_LEN * BACKUP_REGISTER_BYTES { return Err(BackupError::DataTooLarge); } @@ -295,7 +298,7 @@ impl PMUExt for PMU { let sliced = core::slice::from_raw_parts_mut(ptr_u32, reg_count); for i in 0..sliced.len() { - sliced[i] = (*backup).backup[i].read().bits(); + sliced[i] = backup.backup(i).read().bits(); } Ok(()) @@ -303,9 +306,9 @@ impl PMUExt for PMU { fn clear_backup(&self) { unsafe { - let backup = BACKUP::ptr(); + let backup = Backup::steal(); - for backup_r in &(*backup).backup { + for backup_r in backup.backup_iter() { backup_r.write(|w| w.bits(0u32)); } } diff --git a/e310x-hal/src/pwm.rs b/e310x-hal/src/pwm.rs index 7db8bf5..e536c4f 100644 --- a/e310x-hal/src/pwm.rs +++ b/e310x-hal/src/pwm.rs @@ -20,7 +20,7 @@ use core::marker::PhantomData; use core::ops::Deref; -use e310x::{pwm0, PWM0, PWM1, PWM2}; +use e310x::{pwm0, Pwm0, Pwm1, Pwm2}; /// PWM comparator index #[derive(Copy, Clone)] @@ -40,52 +40,52 @@ pub trait Pin { } mod pwm0_impl { - use super::{CmpIndex, Pin, PWM0}; + use super::{CmpIndex, Pin, Pwm0}; use crate::gpio::{gpio0, NoInvert, IOF1}; - impl Pin for gpio0::Pin1> { + impl Pin for gpio0::Pin1> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; } - impl Pin for gpio0::Pin2> { + impl Pin for gpio0::Pin2> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; } - impl Pin for gpio0::Pin3> { + impl Pin for gpio0::Pin3> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; } } mod pwm1_impl { - use super::{CmpIndex, Pin, PWM1}; + use super::{CmpIndex, Pin, Pwm1}; use crate::gpio::{gpio0, NoInvert, IOF1}; - impl Pin for gpio0::Pin19> { + impl Pin for gpio0::Pin19> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; } - impl Pin for gpio0::Pin21> { + impl Pin for gpio0::Pin21> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; } - impl Pin for gpio0::Pin22> { + impl Pin for gpio0::Pin22> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; } } mod pwm2_impl { - use super::{CmpIndex, Pin, PWM2}; + use super::{CmpIndex, Pin, Pwm2}; use crate::gpio::{gpio0, NoInvert, IOF1}; - impl Pin for gpio0::Pin11> { + impl Pin for gpio0::Pin11> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp1; } - impl Pin for gpio0::Pin12> { + impl Pin for gpio0::Pin12> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp2; } - impl Pin for gpio0::Pin13> { + impl Pin for gpio0::Pin13> { const CMP_INDEX: CmpIndex = CmpIndex::Cmp3; } } @@ -141,9 +141,9 @@ macro_rules! pwmx_impl { }; } -pwmx_impl!(PWM0, u8); -pwmx_impl!(PWM1, u16); -pwmx_impl!(PWM2, u16); +pwmx_impl!(Pwm0, u8); +pwmx_impl!(Pwm1, u16); +pwmx_impl!(Pwm2, u16); /// PWM abstraction /// @@ -158,8 +158,8 @@ pub struct Pwm { impl Pwm { /// Configures a PWM device pub fn new(pwm: PWM) -> Self { - pwm.cfg.reset(); - pwm.cfg.write(|w| { + pwm.cfg().reset(); + pwm.cfg().write(|w| { w.zerocmp() .set_bit() .enalways() @@ -167,10 +167,10 @@ impl Pwm { .deglitch() .set_bit() }); - pwm.cmp0.reset(); - pwm.cmp1.reset(); - pwm.cmp2.reset(); - pwm.cmp3.reset(); + pwm.cmp0().reset(); + pwm.cmp1().reset(); + pwm.cmp2().reset(); + pwm.cmp3().reset(); Self { pwm } } } @@ -184,29 +184,29 @@ impl embedded_hal::Pwm for Pwm { fn enable(&mut self, channel: Self::Channel) { match channel.cmp_index { - CmpIndex::Cmp1 => self.pwm.cmp1.write(|w| unsafe { w.bits(u32::MAX) }), - CmpIndex::Cmp2 => self.pwm.cmp2.write(|w| unsafe { w.bits(u32::MAX) }), - CmpIndex::Cmp3 => self.pwm.cmp3.write(|w| unsafe { w.bits(u32::MAX) }), + CmpIndex::Cmp1 => self.pwm.cmp1().write(|w| unsafe { w.bits(u32::MAX) }), + CmpIndex::Cmp2 => self.pwm.cmp2().write(|w| unsafe { w.bits(u32::MAX) }), + CmpIndex::Cmp3 => self.pwm.cmp3().write(|w| unsafe { w.bits(u32::MAX) }), } } fn disable(&mut self, channel: Self::Channel) { match channel.cmp_index { - CmpIndex::Cmp1 => self.pwm.cmp1.reset(), - CmpIndex::Cmp2 => self.pwm.cmp2.reset(), - CmpIndex::Cmp3 => self.pwm.cmp3.reset(), + CmpIndex::Cmp1 => self.pwm.cmp1().reset(), + CmpIndex::Cmp2 => self.pwm.cmp2().reset(), + CmpIndex::Cmp3 => self.pwm.cmp3().reset(), } } fn get_period(&self) -> Self::Time { - PWM::bits_into_cmp_width(self.pwm.cmp0.read().bits()) + PWM::bits_into_cmp_width(self.pwm.cmp0().read().bits()) } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { let duty = match channel.cmp_index { - CmpIndex::Cmp1 => self.pwm.cmp1.read().bits(), - CmpIndex::Cmp2 => self.pwm.cmp2.read().bits(), - CmpIndex::Cmp3 => self.pwm.cmp3.read().bits(), + CmpIndex::Cmp1 => self.pwm.cmp1().read().bits(), + CmpIndex::Cmp2 => self.pwm.cmp2().read().bits(), + CmpIndex::Cmp3 => self.pwm.cmp3().read().bits(), }; PWM::bits_into_cmp_width(duty) } @@ -218,9 +218,9 @@ impl embedded_hal::Pwm for Pwm { fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { let duty = PWM::bits_from_cmp_width(duty.min(self.get_max_duty())); match channel.cmp_index { - CmpIndex::Cmp1 => self.pwm.cmp1.write(|w| unsafe { w.bits(duty) }), - CmpIndex::Cmp2 => self.pwm.cmp2.write(|w| unsafe { w.bits(duty) }), - CmpIndex::Cmp3 => self.pwm.cmp3.write(|w| unsafe { w.bits(duty) }), + CmpIndex::Cmp1 => self.pwm.cmp1().write(|w| unsafe { w.bits(duty) }), + CmpIndex::Cmp2 => self.pwm.cmp2().write(|w| unsafe { w.bits(duty) }), + CmpIndex::Cmp3 => self.pwm.cmp3().write(|w| unsafe { w.bits(duty) }), } } @@ -229,7 +229,7 @@ impl embedded_hal::Pwm for Pwm { P: Into, { let period = PWM::bits_from_cmp_width(period.into()); - self.pwm.count.reset(); - self.pwm.cmp0.write(|w| unsafe { w.bits(period) }); + self.pwm.count().reset(); + self.pwm.cmp0().write(|w| unsafe { w.bits(period) }); } } diff --git a/e310x-hal/src/rtc.rs b/e310x-hal/src/rtc.rs index 2c33044..8cb0274 100644 --- a/e310x-hal/src/rtc.rs +++ b/e310x-hal/src/rtc.rs @@ -1,7 +1,7 @@ //! RTC #![allow(missing_docs)] -use e310x::RTC; +use e310x::Rtc as RTC; pub trait RtcExt { fn constrain(self) -> Rtc; @@ -20,37 +20,41 @@ pub struct Rtc { impl Rtc { #[inline] pub fn is_pending(&self) -> bool { - unsafe { (*RTC::ptr()).rtccfg.read().cmpip().bit() } + unsafe { RTC::steal() }.rtccfg().read().cmpip().bit() } #[inline] pub fn set_scale(&mut self, scale: u8) { - unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.scale().bits(scale)) }; + unsafe { RTC::steal().rtccfg().modify(|_, w| w.scale().bits(scale)) }; } #[inline] pub fn enable(&mut self) { - unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.enalways().bit(true)) } + unsafe { RTC::steal() } + .rtccfg() + .modify(|_, w| w.enalways().bit(true)); } #[inline] pub fn disable(&mut self) { - unsafe { (*RTC::ptr()).rtccfg.modify(|_, w| w.enalways().bit(false)) } + unsafe { RTC::steal() } + .rtccfg() + .modify(|_, w| w.enalways().bit(false)); } #[inline] pub fn is_enabled(&self) -> bool { - unsafe { (*RTC::ptr()).rtccfg.read().enalways().bit() } + unsafe { RTC::steal() }.rtccfg().read().enalways().bit() } #[inline] pub fn rtc_lo(&self) -> u32 { - unsafe { (*RTC::ptr()).rtclo.read().bits() } + unsafe { RTC::steal() }.rtclo().read().bits() } #[inline] pub fn rtc_hi(&self) -> u32 { - unsafe { (*RTC::ptr()).rtchi.read().bits() } + unsafe { RTC::steal() }.rtchi().read().bits() } pub fn rtc(&self) -> u64 { @@ -65,12 +69,12 @@ impl Rtc { #[inline] pub fn set_rtc_lo(&mut self, value: u32) { - unsafe { (*RTC::ptr()).rtclo.write(|w| w.bits(value)) }; + unsafe { RTC::steal().rtclo().write(|w| w.bits(value)) }; } #[inline] pub fn set_rtc_hi(&mut self, value: u16) { - unsafe { (*RTC::ptr()).rtchi.write(|w| w.value().bits(value)) }; + unsafe { RTC::steal().rtchi().write(|w| w.value().bits(value)) }; } pub fn set_rtc(&mut self, value: u64) { @@ -80,11 +84,11 @@ impl Rtc { #[inline] pub fn rtccmp(&self) -> u32 { - unsafe { (*RTC::ptr()).rtccmp.read().bits() } + unsafe { RTC::steal() }.rtccmp().read().bits() } #[inline] pub fn set_rtccmp(&mut self, value: u32) { - unsafe { (*RTC::ptr()).rtccmp.write(|w| w.bits(value)) }; + unsafe { RTC::steal().rtccmp().write(|w| w.bits(value)) }; } } diff --git a/e310x-hal/src/serial.rs b/e310x-hal/src/serial.rs index 0184679..6a284ba 100644 --- a/e310x-hal/src/serial.rs +++ b/e310x-hal/src/serial.rs @@ -24,7 +24,7 @@ use crate::gpio::{gpio0, IOF0}; use crate::time::Bps; use core::mem; #[allow(unused_imports)] -use e310x::{uart0, UART0, UART1}; +use e310x::{uart0, Uart0, Uart1}; // FIXME these should be "closed" traits /// TX pin - DO NOT IMPLEMENT THIS TRAIT @@ -33,20 +33,20 @@ pub unsafe trait TxPin {} /// RX pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait RxPin {} -unsafe impl TxPin for gpio0::Pin17> {} -unsafe impl RxPin for gpio0::Pin16> {} +unsafe impl TxPin for gpio0::Pin17> {} +unsafe impl RxPin for gpio0::Pin16> {} #[cfg(feature = "g002")] mod g002_ims { - use super::{gpio0, RxPin, TxPin, IOF0, UART1}; - unsafe impl TxPin for gpio0::Pin18> {} - unsafe impl RxPin for gpio0::Pin23> {} + use super::{gpio0, RxPin, TxPin, Uart1, IOF0}; + unsafe impl TxPin for gpio0::Pin18> {} + unsafe impl RxPin for gpio0::Pin23> {} } #[doc(hidden)] pub trait UartX: Deref {} -impl UartX for UART0 {} -impl UartX for UART1 {} +impl UartX for Uart0 {} +impl UartX for Uart1 {} /// Serial abstraction pub struct Serial { @@ -73,11 +73,11 @@ impl Serial { { let div = clocks.tlclk().0 / baud_rate.0 - 1; unsafe { - uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(false)); - uart.div.write(|w| w.bits(div)); - uart.txctrl + uart.ie().write(|w| w.txwm().bit(false).rxwm().bit(false)); + uart.div().write(|w| w.bits(div)); + uart.txctrl() .write(|w| w.counter().bits(1).enable().bit(true)); - uart.rxctrl.write(|w| w.enable().bit(true)); + uart.rxctrl().write(|w| w.enable().bit(true)); } Serial { uart, pins } @@ -85,14 +85,16 @@ impl Serial { /// Starts listening for an interrupt event pub fn listen(self) -> Self { - self.uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(true)); + self.uart + .ie() + .write(|w| w.txwm().bit(false).rxwm().bit(true)); self } /// Stops listening for an interrupt event pub fn unlisten(self) -> Self { self.uart - .ie + .ie() .write(|w| w.txwm().bit(false).rxwm().bit(false)); self } @@ -118,7 +120,7 @@ impl serial::Read for Rx { type Error = Infallible; fn read(&mut self) -> nb::Result { - let rxdata = self.uart.rxdata.read(); + let rxdata = self.uart.rxdata().read(); if rxdata.empty().bit_is_set() { Err(::nb::Error::WouldBlock) @@ -132,20 +134,20 @@ impl serial::Write for Tx { type Error = Infallible; fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { - let txdata = self.uart.txdata.read(); + let txdata = self.uart.txdata().read(); if txdata.full().bit_is_set() { Err(::nb::Error::WouldBlock) } else { unsafe { - self.uart.txdata.write(|w| w.data().bits(byte)); + self.uart.txdata().write(|w| w.data().bits(byte)); } Ok(()) } } fn flush(&mut self) -> nb::Result<(), Infallible> { - if self.uart.ip.read().txwm().bit_is_set() { + if self.uart.ip().read().txwm().bit_is_set() { // FIFO count is below the receive watermark (1) Ok(()) } else { @@ -155,26 +157,26 @@ impl serial::Write for Tx { } // Backward compatibility -impl Serial { +impl Serial { /// Configures a UART peripheral to provide serial communication #[deprecated(note = "Please use Serial::new function instead")] - pub fn uart0(uart: UART0, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self + pub fn uart0(uart: Uart0, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self where - TX: TxPin, - RX: RxPin, + TX: TxPin, + RX: RxPin, { Self::new(uart, pins, baud_rate, clocks) } } #[cfg(feature = "g002")] -impl Serial { +impl Serial { /// Configures a UART peripheral to provide serial communication #[deprecated(note = "Please use Serial::new function instead")] - pub fn uart1(uart: UART1, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self + pub fn uart1(uart: Uart1, pins: (TX, RX), baud_rate: Bps, clocks: Clocks) -> Self where - TX: TxPin, - RX: RxPin, + TX: TxPin, + RX: RxPin, { Self::new(uart, pins, baud_rate, clocks) } diff --git a/e310x-hal/src/spi.rs b/e310x-hal/src/spi.rs index d508849..e5fe5c4 100644 --- a/e310x-hal/src/spi.rs +++ b/e310x-hal/src/spi.rs @@ -24,7 +24,7 @@ //! - Interrupt::QSPI2 //! //! # Exclusive Bus usage example -//!``` +//!```ignore //! let pins = (mosi, miso, sck, cs0); //! let spi_bus = SpiBus::new(p.QSPI1, pins); //! @@ -35,7 +35,7 @@ //!``` //! //! # Shared Bus usage example -//!``` +//!```ignore //! let pins = (mosi, miso, sck); //! let spi_bus = SpiBus::shared(p.QSPI1, pins); //! @@ -62,3 +62,5 @@ pub use exclusive_device::*; pub use shared_bus::*; pub use shared_device::*; pub use traits::*; + +pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; diff --git a/e310x-hal/src/spi/bus.rs b/e310x-hal/src/spi/bus.rs index 94ea72b..4be10be 100644 --- a/e310x-hal/src/spi/bus.rs +++ b/e310x-hal/src/spi/bus.rs @@ -1,7 +1,7 @@ use core::convert::Infallible; use embedded_hal::blocking::spi::Operation; pub use embedded_hal::blocking::spi::{Transfer, Write, WriteIter}; -pub use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal::spi::{FullDuplex, Phase, Polarity}; use nb; @@ -36,25 +36,27 @@ where PINS: Pins, { self.spi - .sckdiv + .sckdiv() .write(|w| unsafe { w.div().bits(config.clock_divisor as u16) }); if let Some(index) = cs_index { - self.spi.csid.write(|w| unsafe { w.bits(index) }); + self.spi.csid().write(|w| unsafe { w.bits(index) }); } - self.spi.csmode.write(|w| w.mode().variant(config.cs_mode)); + self.spi + .csmode() + .write(|w| w.mode().variant(config.cs_mode)); // Set CS pin polarity to high - self.spi.csdef.reset(); + self.spi.csdef().reset(); // Set SPI mode let phase = config.mode.phase == Phase::CaptureOnSecondTransition; let polarity = config.mode.polarity == Polarity::IdleHigh; self.spi - .sckmode + .sckmode() .write(|w| w.pha().bit(phase).pol().bit(polarity)); - self.spi.fmt.write(|w| unsafe { + self.spi.fmt().write(|w| unsafe { w.proto().single(); w.endian().big(); // Transmit most-significant bit (MSB) first w.dir().rx(); @@ -63,18 +65,18 @@ where // Set watermark levels self.spi - .txmark + .txmark() .write(|w| unsafe { w.txmark().bits(config.txmark) }); self.spi - .rxmark + .rxmark() .write(|w| unsafe { w.rxmark().bits(config.rxmark) }); // set delays - self.spi.delay0.write(|w| unsafe { + self.spi.delay0().write(|w| unsafe { w.cssck().bits(config.delays.cssck); // delay between assert and clock w.sckcs().bits(config.delays.sckcs) // delay between clock and de-assert }); - self.spi.delay1.write(|w| unsafe { + self.spi.delay1().write(|w| unsafe { w.intercs().bits(config.delays.intercs); // delay between CS re-assets w.interxfr().bits(config.delays.interxfr) // intra-frame delay without CS re-asserts }); @@ -84,27 +86,27 @@ where fn wait_for_rxfifo(&self) { // Ensure that RX FIFO is empty - while self.spi.rxdata.read().empty().bit_is_clear() {} + while self.spi.rxdata().read().empty().bit_is_clear() {} } /// Starts frame by flagging CS assert, unless CSMODE = OFF pub(crate) fn start_frame(&mut self) { - if !self.spi.csmode.read().mode().is_off() { - self.spi.csmode.write(|w| w.mode().hold()); + if !self.spi.csmode().read().mode().is_off() { + self.spi.csmode().write(|w| w.mode().hold()); } } /// Finishes frame flagging CS deassert, unless CSMODE = OFF pub(crate) fn end_frame(&mut self) { - if !self.spi.csmode.read().mode().is_off() { - self.spi.csmode.write(|w| w.mode().auto()); + if !self.spi.csmode().read().mode().is_off() { + self.spi.csmode().write(|w| w.mode().auto()); } } // ex-traits now only accessible via devices pub(crate) fn read(&mut self) -> nb::Result { - let rxdata = self.spi.rxdata.read(); + let rxdata = self.spi.rxdata().read(); if rxdata.empty().bit_is_set() { Err(nb::Error::WouldBlock) @@ -114,12 +116,12 @@ where } pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - let txdata = self.spi.txdata.read(); + let txdata = self.spi.txdata().read(); if txdata.full().bit_is_set() { Err(nb::Error::WouldBlock) } else { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + self.spi.txdata().write(|w| unsafe { w.data().bits(byte) }); Ok(()) } } @@ -132,14 +134,14 @@ where self.wait_for_rxfifo(); while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + if iwrite < words.len() && self.spi.txdata().read().full().bit_is_clear() { let byte = unsafe { words.get_unchecked(iwrite) }; iwrite += 1; - self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + self.spi.txdata().write(|w| unsafe { w.data().bits(*byte) }); } if iread < iwrite { - let data = self.spi.rxdata.read(); + let data = self.spi.rxdata().read(); if data.empty().bit_is_clear() { unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; iread += 1; @@ -158,15 +160,15 @@ where self.wait_for_rxfifo(); while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { + if iwrite < words.len() && self.spi.txdata().read().full().bit_is_clear() { let byte = unsafe { words.get_unchecked(iwrite) }; iwrite += 1; - self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); + self.spi.txdata().write(|w| unsafe { w.data().bits(*byte) }); } if iread < iwrite { // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { + if self.spi.rxdata().read().empty().bit_is_clear() { iread += 1; } } @@ -188,9 +190,9 @@ where self.wait_for_rxfifo(); while has_data || read_count > 0 { - if has_data && self.spi.txdata.read().full().bit_is_clear() { + if has_data && self.spi.txdata().read().full().bit_is_clear() { if let Some(byte) = iter.next() { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + self.spi.txdata().write(|w| unsafe { w.data().bits(byte) }); read_count += 1; } else { has_data = false; @@ -199,7 +201,7 @@ where if read_count > 0 { // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { + if self.spi.rxdata().read().empty().bit_is_clear() { read_count -= 1; } } diff --git a/e310x-hal/src/spi/config.rs b/e310x-hal/src/spi/config.rs index 6b30e72..61a9e8d 100644 --- a/e310x-hal/src/spi/config.rs +++ b/e310x-hal/src/spi/config.rs @@ -1,4 +1,4 @@ -use e310x::qspi0::csmode::MODE_A; +use e310x::qspi0::csmode::Mode as MODE_A; use embedded_hal::spi::Mode; use crate::{clock::Clocks, time::Hertz}; @@ -44,7 +44,7 @@ impl SpiConfig { Self { mode, clock_divisor, - cs_mode: MODE_A::HOLD, + cs_mode: MODE_A::Hold, txmark: 1, rxmark: 0, delays: SpiDelayConfig::default(), diff --git a/e310x-hal/src/spi/shared_bus.rs b/e310x-hal/src/spi/shared_bus.rs index 67b9e06..6c75ebd 100644 --- a/e310x-hal/src/spi/shared_bus.rs +++ b/e310x-hal/src/spi/shared_bus.rs @@ -1,6 +1,5 @@ use core::cell::RefCell; use core::ops::Deref; -pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use riscv::interrupt; use super::{PinCS, PinsNoCS, SpiBus, SpiConfig, SpiSharedDevice, SpiX}; diff --git a/e310x-hal/src/spi/traits.rs b/e310x-hal/src/spi/traits.rs index 16f91f5..a3b3dfc 100644 --- a/e310x-hal/src/spi/traits.rs +++ b/e310x-hal/src/spi/traits.rs @@ -1,12 +1,12 @@ /// Helper traits for SPI pins use core::ops::Deref; -use e310x::{qspi0, QSPI0, QSPI1, QSPI2}; +use e310x::{qspi0, Qspi0, Qspi1, Qspi2}; #[doc(hidden)] pub trait SpiX: Deref + private::Sealed {} -impl SpiX for QSPI0 {} -impl SpiX for QSPI1 {} -impl SpiX for QSPI2 {} +impl SpiX for Qspi0 {} +impl SpiX for Qspi1 {} +impl SpiX for Qspi2 {} /// SPI pins - DO NOT IMPLEMENT THIS TRAIT /// @@ -32,13 +32,13 @@ pub trait PinCS: private::Sealed { } /* SPI0 pins */ -impl Pins for () { +impl Pins for () { const CS_INDEX: Option = Some(0); } /* SPI1 pins */ mod spi1_impl { - use super::{PinCS, Pins, PinsNoCS, QSPI1}; + use super::{PinCS, Pins, PinsNoCS, Qspi1}; use crate::gpio::gpio0; use crate::gpio::{NoInvert, IOF0}; @@ -51,66 +51,66 @@ mod spi1_impl { type CS3 = gpio0::Pin10>; // ensure only the correct CS pins can be used to make SpiSharedDevice instances - impl PinCS for CS0 { + impl PinCS for CS0 { const CS_INDEX: u32 = 0; } - impl PinCS for CS1 { + impl PinCS for CS1 { const CS_INDEX: u32 = 1; } - impl PinCS for CS2 { + impl PinCS for CS2 { const CS_INDEX: u32 = 2; } - impl PinCS for CS3 { + impl PinCS for CS3 { const CS_INDEX: u32 = 3; } - impl PinsNoCS for (MOSI, MISO, SCK) {} - impl PinsNoCS for (MOSI, (), SCK) {} - impl PinsNoCS for ((), MISO, SCK) {} + impl PinsNoCS for (MOSI, MISO, SCK) {} + impl PinsNoCS for (MOSI, (), SCK) {} + impl PinsNoCS for ((), MISO, SCK) {} - impl Pins for (MOSI, MISO, SCK) { + impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, (), SCK) { + impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } - impl Pins for ((), MISO, SCK) { + impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, MISO, SCK, CS0) { + impl Pins for (MOSI, MISO, SCK, CS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, (), SCK, CS0) { + impl Pins for (MOSI, (), SCK, CS0) { const CS_INDEX: Option = Some(0); } - impl Pins for ((), MISO, SCK, CS0) { + impl Pins for ((), MISO, SCK, CS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, MISO, SCK, CS1) { + impl Pins for (MOSI, MISO, SCK, CS1) { const CS_INDEX: Option = Some(1); } - impl Pins for (MOSI, (), SCK, CS1) { + impl Pins for (MOSI, (), SCK, CS1) { const CS_INDEX: Option = Some(1); } - impl Pins for ((), MISO, SCK, CS1) { + impl Pins for ((), MISO, SCK, CS1) { const CS_INDEX: Option = Some(1); } - impl Pins for (MOSI, MISO, SCK, CS2) { + impl Pins for (MOSI, MISO, SCK, CS2) { const CS_INDEX: Option = Some(2); } - impl Pins for (MOSI, (), SCK, CS2) { + impl Pins for (MOSI, (), SCK, CS2) { const CS_INDEX: Option = Some(2); } - impl Pins for ((), MISO, SCK, CS2) { + impl Pins for ((), MISO, SCK, CS2) { const CS_INDEX: Option = Some(2); } - impl Pins for (MOSI, MISO, SCK, CS3) { + impl Pins for (MOSI, MISO, SCK, CS3) { const CS_INDEX: Option = Some(3); } - impl Pins for (MOSI, (), SCK, CS3) { + impl Pins for (MOSI, (), SCK, CS3) { const CS_INDEX: Option = Some(3); } - impl Pins for ((), MISO, SCK, CS3) { + impl Pins for ((), MISO, SCK, CS3) { const CS_INDEX: Option = Some(3); } @@ -143,7 +143,7 @@ mod spi1_impl { /* SPI2 pins */ mod spi2_impl { - use super::{PinCS, Pins, PinsNoCS, QSPI2}; + use super::{PinCS, Pins, PinsNoCS, Qspi2}; use crate::gpio::gpio0; use crate::gpio::{NoInvert, IOF0}; @@ -152,30 +152,30 @@ mod spi2_impl { type SCK = gpio0::Pin29>; type CS0 = gpio0::Pin26>; - impl PinCS for CS0 { + impl PinCS for CS0 { const CS_INDEX: u32 = 0; } - impl PinsNoCS for (MOSI, MISO, SCK) {} - impl PinsNoCS for (MOSI, (), SCK) {} - impl PinsNoCS for ((), MISO, SCK) {} + impl PinsNoCS for (MOSI, MISO, SCK) {} + impl PinsNoCS for (MOSI, (), SCK) {} + impl PinsNoCS for ((), MISO, SCK) {} - impl Pins for (MOSI, MISO, SCK) { + impl Pins for (MOSI, MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, (), SCK) { + impl Pins for (MOSI, (), SCK) { const CS_INDEX: Option = None; } - impl Pins for ((), MISO, SCK) { + impl Pins for ((), MISO, SCK) { const CS_INDEX: Option = None; } - impl Pins for (MOSI, MISO, SCK, CS0) { + impl Pins for (MOSI, MISO, SCK, CS0) { const CS_INDEX: Option = Some(0); } - impl Pins for (MOSI, (), SCK, CS0) { + impl Pins for (MOSI, (), SCK, CS0) { const CS_INDEX: Option = Some(0); } - impl Pins for ((), MISO, SCK, CS0) { + impl Pins for ((), MISO, SCK, CS0) { const CS_INDEX: Option = Some(0); } @@ -200,7 +200,7 @@ mod private { impl Sealed for () {} - impl Sealed for super::QSPI0 {} - impl Sealed for super::QSPI1 {} - impl Sealed for super::QSPI2 {} + impl Sealed for super::Qspi0 {} + impl Sealed for super::Qspi1 {} + impl Sealed for super::Qspi2 {} } diff --git a/e310x-hal/src/wdog.rs b/e310x-hal/src/wdog.rs index 2abba57..6599b55 100644 --- a/e310x-hal/src/wdog.rs +++ b/e310x-hal/src/wdog.rs @@ -1,6 +1,6 @@ //! Watchdog #![allow(missing_docs)] -use e310x::WDOG; +use e310x::Wdog as WDOG; pub trait WdogExt { fn configure(self) -> WdogCfg; @@ -56,8 +56,9 @@ impl WdogCfg { pub fn freeze(self) -> Wdog { unsafe { - (*WDOG::ptr()).wdogkey.write(|w| w.bits(0x51F15E)); - (*WDOG::ptr()).wdogcfg.write(|w| { + let wdog = WDOG::steal(); + wdog.wdogkey().write(|w| w.bits(0x51F15E)); + wdog.wdogcfg().write(|w| { w.scale() .bits(self.scale) .rsten() @@ -81,23 +82,23 @@ pub struct Wdog { impl Wdog { #[inline] fn unlock(&mut self) { - unsafe { (*WDOG::ptr()).wdogkey.write(|w| w.bits(0x51F15E)) }; + unsafe { WDOG::steal().wdogkey().write(|w| w.bits(0x51F15E)) }; } pub fn is_pending(&self) -> bool { - unsafe { (*WDOG::ptr()).wdogcfg.read().cmpip().bit() } + unsafe { WDOG::steal() }.wdogcfg().read().cmpip().bit() } pub fn feed(&mut self) { self.unlock(); - unsafe { (*WDOG::ptr()).wdogfeed.write(|w| w.bits(0xD09F00D)) }; + unsafe { WDOG::steal().wdogfeed().write(|w| w.bits(0xD09F00D)) }; } pub fn cmp(&self) -> u16 { - unsafe { (*WDOG::ptr()).wdogcmp.read().value().bits() } + unsafe { WDOG::steal() }.wdogcmp().read().value().bits() } pub fn set_cmp(&mut self, value: u16) { - unsafe { (*WDOG::ptr()).wdogcmp.write(|w| w.value().bits(value)) }; + unsafe { WDOG::steal().wdogcmp().write(|w| w.value().bits(value)) }; } } diff --git a/e310x/CHANGELOG.md b/e310x/CHANGELOG.md index 4548bd1..6382762 100644 --- a/e310x/CHANGELOG.md +++ b/e310x/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed -- Bump MSRV to 1.65.0 +- Bump MSRV to 1.65.0 (check Cargo.toml) - Regenerate code with `svd2rust` v0.33.4 ## [v0.11.0] diff --git a/e310x/Cargo.toml b/e310x/Cargo.toml index 6a97ead..89d32d8 100644 --- a/e310x/Cargo.toml +++ b/e310x/Cargo.toml @@ -7,7 +7,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "With svd2rust generated peripherals for Freedom E310 MCU's." keywords = ["riscv", "register", "peripheral"] license = "ISC" -rust-version = "1.59" +rust-version = "1.65" edition = "2021" [dependencies] From a783004c93e4f3c1b5052d3983b67db08ae2c84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Thu, 26 Sep 2024 14:58:46 +0200 Subject: [PATCH 312/315] Using portable-atomic always --- .cargo/config.toml | 7 +++++++ .github/workflows/e310x-hal.yaml | 11 +++++----- .github/workflows/e310x.yaml | 2 ++ e310x-hal/CHANGELOG.md | 3 ++- e310x-hal/Cargo.toml | 4 +--- e310x-hal/src/gpio.rs | 3 --- e310x-hal/src/lib.rs | 36 ++++++++++++++++++++++++++++++++ 7 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..2dbabf9 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +[target.'cfg(all(target_arch = "riscv32", target_os = "none"))'] +rustflags = [ + "--cfg", "portable_atomic_target_feature=\"zaamo\"", +] + +[build] +target = "riscv32imc-unknown-none-elf" diff --git a/.github/workflows/e310x-hal.yaml b/.github/workflows/e310x-hal.yaml index 043e24d..db7ec55 100644 --- a/.github/workflows/e310x-hal.yaml +++ b/.github/workflows/e310x-hal.yaml @@ -13,9 +13,6 @@ jobs: matrix: # All generated code should be running on stable now, MRSV is 1.65.0 toolchain: [ stable, nightly, 1.65.0 ] - target: - - riscv32imc-unknown-none-elf - - riscv32imac-unknown-none-elf # TODO e310x is not a purely IMAC core include: # Nightly is only for reference and allowed to fail - toolchain: nightly @@ -27,11 +24,11 @@ jobs: - name: Update Rust toolchain run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - name: Install Rust target - run: rustup target install ${{ matrix.target }} + run: rustup target install riscv32imc-unknown-none-elf - name: Build (no features) - run: cargo build --package e310x-hal --target ${{ matrix.target }} + run: cargo build --package e310x-hal --target riscv32imc-unknown-none-elf - name: Build (all features) - run: cargo build --package e310x-hal --target ${{ matrix.target }} --all-features + run: cargo build --package e310x-hal --target riscv32imc-unknown-none-elf --all-features # On MacOS and Ubuntu, we at least make sure that the crate builds and links. # On Windows, linking fails when the rt feature is enabled. @@ -44,6 +41,8 @@ jobs: - uses: actions/checkout@v4 - name: Update Rust toolchain run: rustup update stable && rustup default stable + - name: Rename .cargo/config to .cargo/config.bak to ignore it + run: mv .cargo/config.toml .cargo/config.bak - name: Build (no features) run: cargo test --package e310x-hal - name: Build (all features) diff --git a/.github/workflows/e310x.yaml b/.github/workflows/e310x.yaml index d7da24f..5c110c9 100644 --- a/.github/workflows/e310x.yaml +++ b/.github/workflows/e310x.yaml @@ -44,6 +44,8 @@ jobs: - uses: actions/checkout@v4 - name: Update Rust toolchain run: rustup update stable && rustup default stable + - name: Rename .cargo/config to .cargo/config.bak to ignore it + run: mv .cargo/config.toml .cargo/config.bak - name: Build (no features) run: cargo test --package e310x - name: Build (all features) diff --git a/e310x-hal/CHANGELOG.md b/e310x-hal/CHANGELOG.md index d2e709d..2b6dd98 100644 --- a/e310x-hal/CHANGELOG.md +++ b/e310x-hal/CHANGELOG.md @@ -8,9 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed +- Use `portable-atomic` with `zaamo` feature to use native `amo*` operations. +- Official target is now `riscv32imc-unknown-none-elf`, as it does not fully support the A extension. - Update `e310x` dependency and adapt code - Bump MSRV to 1.65.0 (check Cargo.toml) -- Use `portable-atomic` to allow builds on `riscv32imc-unknown-none-elf`` targets when needed. ## [v0.10.0] - 2023-03-28 diff --git a/e310x-hal/Cargo.toml b/e310x-hal/Cargo.toml index 052429d..69b6372 100644 --- a/e310x-hal/Cargo.toml +++ b/e310x-hal/Cargo.toml @@ -15,9 +15,7 @@ embedded-hal = { version = "0.2.6", features = ["unproven"] } nb = "1.0.0" riscv = { version = "0.10.1", features = ["critical-section-single-hart"] } e310x = { path = "../e310x", version = "0.11.0", features = ["rt", "critical-section"] } - -[target.'cfg(not(target_has_atomic = "32"))'.dependencies] -portable-atomic = { version = "1.4", default-features = false, features = ["unsafe-assume-single-core"] } +portable-atomic = { version = "1.9", default-features = false} [features] g002 = ["e310x/g002"] diff --git a/e310x-hal/src/gpio.rs b/e310x-hal/src/gpio.rs index fb6d289..14604b7 100644 --- a/e310x-hal/src/gpio.rs +++ b/e310x-hal/src/gpio.rs @@ -2,9 +2,6 @@ use core::marker::PhantomData; -#[cfg(target_has_atomic = "32")] -use core::sync::atomic::{AtomicU32, Ordering}; -#[cfg(not(target_has_atomic = "32"))] use portable_atomic::{AtomicU32, Ordering}; /// GpioExt trait extends the GPIO0 peripheral. diff --git a/e310x-hal/src/lib.rs b/e310x-hal/src/lib.rs index b0f50b5..40bf01a 100644 --- a/e310x-hal/src/lib.rs +++ b/e310x-hal/src/lib.rs @@ -2,6 +2,42 @@ //! //! This is an implementation of the [`embedded-hal`] traits for the E310x //! family of microcontrollers. +//! +//! # Building an application for the E310x chips +//! +//! The E310x chips implement the [Zaamo](https://github.com/riscv/riscv-zaamo-zalrsc/blob/main/zaamo-zalrsc.adoc) +//! extension for atomic instructions. This means that it *partially* supports the `A` +//! extension for atomic. Specifically, it supports the `amo*` instructions, but not the +//! `lr*` and `sc*` instructions. +//! +//! It is discouraged to use the `riscv32imac-unknown-none-elf` target for E310x chips, as it +//! will potentially generate code that uses the `lr*` and `sc*` instructions, which are not +//! supported by the E310x chips. Thus, it is recommended to use `riscv32imc-unknown-none-elf`. +//! +//! # Working with atomic operations +//! +//! If you are using the `riscv32imc-unknown-none-elf` target, you will notice that +//! `core::sync::atomic` is not available. To work around this, you can use the +//! [`portable-atomic`](https://docs.rs/portable-atomic/1.8.0/portable_atomic/) crate. +//! This crate allows us to use native `amo*` instructions on the E310x chips without requiring +//! the `A` extension. Furthermore, you can emulate the `lr*` and `sc*` instructions if needed. +//! +//! Thus, the recommended way to work with E310x chips is: +//! +//! 1. Compile your code against the `riscv32imc-unknown-none-elf` target. +//! 2. Add the following configuration to your `.cargo/config.toml`: +//! +//! ```toml +//! [target.'cfg(all(target_arch = "riscv32", target_os = "none"))'] +//! rustflags = [ +//! "--cfg", "portable_atomic_target_feature=\"zaamo\"", +//! ] +//! +//! [build] +//! target = "riscv32imc-unknown-none-elf" +//! ``` +//! +//! This will ensure that the `portable-atomic` crate is correctly configured to work with the E310x chips. #![deny(missing_docs)] #![no_std] From 17b9b334ae58be0c04684a2e3336ffc4112e8e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 7 Oct 2024 18:55:14 +0200 Subject: [PATCH 313/315] inline assembly for flash --- .travis.yml | 31 ------------------------------- CHANGELOG.md | 1 + assemble.sh | 11 ----------- bin/flash.a | Bin 2222 -> 0 bytes build.rs | 6 ------ flash.S | 45 --------------------------------------------- src/flash.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 51 insertions(+), 93 deletions(-) delete mode 100644 .travis.yml delete mode 100755 assemble.sh delete mode 100644 bin/flash.a delete mode 100644 flash.S diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1e9dc7a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: rust - -env: - - TARGET=x86_64-unknown-linux-gnu - - TARGET=riscv32imac-unknown-none-elf - -rust: - - nightly - - stable - -if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) - - -install: - - ci/install.sh - -script: - - ci/script.sh - - -cache: cargo - -branches: - only: - - master - - staging - - trying - -notifications: - email: - on_success: never diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d128e..e229ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Use inline assembly instead of binary blobs for flash ## [v0.12.0] - 2023-03-28 - Update e310x-hal to v0.11 with new svd2rust generated code diff --git a/assemble.sh b/assemble.sh deleted file mode 100755 index 3a04536..0000000 --- a/assemble.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -euxo pipefail - -# remove existing blobs because otherwise this will append object files to the old blobs -rm -f bin/*.a - -riscv64-unknown-elf-gcc -ggdb3 -fdebug-prefix-map=$(pwd)=/hifive1 -c -mabi=ilp32 -march=rv32imac flash.S -o bin/flash.o -riscv64-unknown-elf-ar crs bin/flash.a bin/flash.o - -rm bin/flash.o diff --git a/bin/flash.a b/bin/flash.a deleted file mode 100644 index 4c734e21c25daa429a7aced6fcbdaeb1545f37ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2222 zcma)6&rcIU6n@ifD@7=U5+x#L6-A6@DGS2I5J;>hhUft`Mh~!s0!_+~Y?lU&iNup8 z9zE#IgE2jL@Fs~~JaF{D-=GJNCSFWT)bGuY?Y2PlCG+O{-n{wV%(!+*wA$x#^?q;AU6`@G2Xze*&>k9?qPvU<7iQ!4-Db2dS3wH^45 z+D`x51bxeYxsmv-d^VYkf8R~yYrBuPUPH;E6YxU(O1Hzy@>qhOjxYMEK(qgGv9Hy(+Z`o5bw(E?zoYsc+2PQ~76zws|&2-k8 z8ieypmH8?OKFfq(9dS$UdTw@woyTq-&dfQew;H}Se;KuElW!psHH&b#(ZD`DI&2X> zSTvyX>u1rdhZ}+XmT->Zoe>^F0E_rh)Xkz~Q@u1IL}Ot}T%P4Xgm(d7i0}{sSadi_ z!P}d7x`}6~M@M*%8SIyw>6{Jc#)jdCwRfrU6>~1u!4AfsH={T0Fy=+V&Z7z55R5ya zm&5l(=%uiP&91bPQyGfi^RC8$7D_5qdWfV?90xqqhWX<^a+p2;W^}X6yk12J_e* z5SxKEeeG!jJX$vc!uOWz^0ha0p8~U94vlRSq)$QVd5qgj-OC`{3j}RL(6b)fbF^sP z!AMwCdI%(U`J7)-buF1x|xns<~BCv(Vzk{P_tjF(^pE&eFTL9Vbd+`3F Nd6N*>4rkTt{sl;fv@QSu diff --git a/build.rs b/build.rs index ec4ac5f..c16de98 100644 --- a/build.rs +++ b/build.rs @@ -44,10 +44,4 @@ fn main() { fs::copy("hifive1-link.x", out_dir.join("hifive1-link.x")).unwrap(); println!("cargo:rerun-if-changed=hifive1-link.x"); - - // Copy library with flash setup code - let name = env::var("CARGO_PKG_NAME").unwrap(); - fs::copy("bin/flash.a", out_dir.join(format!("lib{}.a", name))).unwrap(); - println!("cargo:rustc-link-lib=static={}", name); - println!("cargo:rerun-if-changed=bin/flash.a"); } diff --git a/flash.S b/flash.S deleted file mode 100644 index 53dd795..0000000 --- a/flash.S +++ /dev/null @@ -1,45 +0,0 @@ -.cfi_sections .debug_frame - -.section .data._setup_is25lp -.global _setup_is25lp -.cfi_startproc -_setup_is25lp: - li a1, 0x10014000 // QSPI0 base address - - // Disable mapped region - sw zero,96(a1) // fctrl.en = 0 - - // Construct ffmt value for 4 dummy cycles - li a2, 0x00BB1447 - - beqz a0, 2f - - // We need to set 8 dummy cycles instead of 4. - // Issue a "Set Read Parameters" command. - - li a0,2 - sw a0,24(a1) // csmode = HOLD - li a0,0xC0 - sw a0,72(a1) // txdata = 0xC0 - li a0,0xF0 - sw a0,72(a1) // txdata = 0xF0 - sw zero,24(a1) // csmode = AUTO - - // Discard two response bytes -1: lw a0,76(a1) - bltz a0,1b -1: lw a0,76(a1) - bltz a0,1b - - addi a2,a2,0x40 // ffmt: 4 -> 8 dummy cycles -2: - sw a2,100(a1) // Write ffmt - - // Enable mapped region - li a0, 1 - sw a0,96(a1) // fctrl.en = 1 - ret - - -.cfi_endproc -.size _setup_is25lp, . - _setup_is25lp diff --git a/src/flash.rs b/src/flash.rs index e138c99..4208379 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -3,6 +3,56 @@ use e310x_hal::clock::Clocks; use e310x_hal::e310x::QSPI0; +#[cfg(target_arch = "riscv32")] +core::arch::global_asm!( + r#" + .cfi_sections .debug_frame + + .section .data._setup_is25lp + .global _setup_is25lp + .cfi_startproc + _setup_is25lp: + li a1, 0x10014000 // QSPI0 base address + + // Disable mapped region + sw zero,96(a1) // fctrl.en = 0 + + // Construct ffmt value for 4 dummy cycles + li a2, 0x00BB1447 + + beqz a0, 2f + + // We need to set 8 dummy cycles instead of 4. + // Issue a "Set Read Parameters" command. + + li a0,2 + sw a0,24(a1) // csmode = HOLD + li a0,0xC0 + sw a0,72(a1) // txdata = 0xC0 + li a0,0xF0 + sw a0,72(a1) // txdata = 0xF0 + sw zero,24(a1) // csmode = AUTO + + // Discard two response bytes + 1: lw a0,76(a1) + bltz a0,1b + 1: lw a0,76(a1) + bltz a0,1b + + addi a2,a2,0x40 // ffmt: 4 -> 8 dummy cycles + 2: + sw a2,100(a1) // Write ffmt + + // Enable mapped region + li a0, 1 + sw a0,96(a1) // fctrl.en = 1 + ret + + .cfi_endproc + .size _setup_is25lp, . - _setup_is25lp + "# +); + /// Configure SPI Flash interface to maximum supported speed #[inline(always)] pub fn configure_spi_flash(qspi: &QSPI0, clocks: &Clocks) { From 4d4e23fc45c6d148d18359752ebaafeee0a9f439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 7 Oct 2024 18:58:05 +0200 Subject: [PATCH 314/315] prepare for workspace --- {.github => hifive1/.github}/CODEOWNERS | 0 {.github => hifive1/.github}/bors.toml | 0 {.github => hifive1/.github}/workflows/ci.yaml | 0 {.github => hifive1/.github}/workflows/rustfmt.yaml | 0 .gitignore => hifive1/.gitignore | 0 CHANGELOG.md => hifive1/CHANGELOG.md | 0 CODE_OF_CONDUCT.md => hifive1/CODE_OF_CONDUCT.md | 0 Cargo.toml => hifive1/Cargo.toml | 0 README.md => hifive1/README.md | 0 build.rs => hifive1/build.rs | 0 hifive1-link.x => hifive1/hifive1-link.x | 0 memory-hifive1-revb.x => hifive1/memory-hifive1-revb.x | 0 memory-hifive1.x => hifive1/memory-hifive1.x | 0 memory-lofive-r1.x => hifive1/memory-lofive-r1.x | 0 {src => hifive1/src}/clock.rs | 0 {src => hifive1/src}/flash.rs | 0 {src => hifive1/src}/gpio.rs | 0 {src => hifive1/src}/led.rs | 0 {src => hifive1/src}/lib.rs | 0 {src => hifive1/src}/stdout.rs | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename {.github => hifive1/.github}/CODEOWNERS (100%) rename {.github => hifive1/.github}/bors.toml (100%) rename {.github => hifive1/.github}/workflows/ci.yaml (100%) rename {.github => hifive1/.github}/workflows/rustfmt.yaml (100%) rename .gitignore => hifive1/.gitignore (100%) rename CHANGELOG.md => hifive1/CHANGELOG.md (100%) rename CODE_OF_CONDUCT.md => hifive1/CODE_OF_CONDUCT.md (100%) rename Cargo.toml => hifive1/Cargo.toml (100%) rename README.md => hifive1/README.md (100%) rename build.rs => hifive1/build.rs (100%) rename hifive1-link.x => hifive1/hifive1-link.x (100%) rename memory-hifive1-revb.x => hifive1/memory-hifive1-revb.x (100%) rename memory-hifive1.x => hifive1/memory-hifive1.x (100%) rename memory-lofive-r1.x => hifive1/memory-lofive-r1.x (100%) rename {src => hifive1/src}/clock.rs (100%) rename {src => hifive1/src}/flash.rs (100%) rename {src => hifive1/src}/gpio.rs (100%) rename {src => hifive1/src}/led.rs (100%) rename {src => hifive1/src}/lib.rs (100%) rename {src => hifive1/src}/stdout.rs (100%) diff --git a/.github/CODEOWNERS b/hifive1/.github/CODEOWNERS similarity index 100% rename from .github/CODEOWNERS rename to hifive1/.github/CODEOWNERS diff --git a/.github/bors.toml b/hifive1/.github/bors.toml similarity index 100% rename from .github/bors.toml rename to hifive1/.github/bors.toml diff --git a/.github/workflows/ci.yaml b/hifive1/.github/workflows/ci.yaml similarity index 100% rename from .github/workflows/ci.yaml rename to hifive1/.github/workflows/ci.yaml diff --git a/.github/workflows/rustfmt.yaml b/hifive1/.github/workflows/rustfmt.yaml similarity index 100% rename from .github/workflows/rustfmt.yaml rename to hifive1/.github/workflows/rustfmt.yaml diff --git a/.gitignore b/hifive1/.gitignore similarity index 100% rename from .gitignore rename to hifive1/.gitignore diff --git a/CHANGELOG.md b/hifive1/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to hifive1/CHANGELOG.md diff --git a/CODE_OF_CONDUCT.md b/hifive1/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to hifive1/CODE_OF_CONDUCT.md diff --git a/Cargo.toml b/hifive1/Cargo.toml similarity index 100% rename from Cargo.toml rename to hifive1/Cargo.toml diff --git a/README.md b/hifive1/README.md similarity index 100% rename from README.md rename to hifive1/README.md diff --git a/build.rs b/hifive1/build.rs similarity index 100% rename from build.rs rename to hifive1/build.rs diff --git a/hifive1-link.x b/hifive1/hifive1-link.x similarity index 100% rename from hifive1-link.x rename to hifive1/hifive1-link.x diff --git a/memory-hifive1-revb.x b/hifive1/memory-hifive1-revb.x similarity index 100% rename from memory-hifive1-revb.x rename to hifive1/memory-hifive1-revb.x diff --git a/memory-hifive1.x b/hifive1/memory-hifive1.x similarity index 100% rename from memory-hifive1.x rename to hifive1/memory-hifive1.x diff --git a/memory-lofive-r1.x b/hifive1/memory-lofive-r1.x similarity index 100% rename from memory-lofive-r1.x rename to hifive1/memory-lofive-r1.x diff --git a/src/clock.rs b/hifive1/src/clock.rs similarity index 100% rename from src/clock.rs rename to hifive1/src/clock.rs diff --git a/src/flash.rs b/hifive1/src/flash.rs similarity index 100% rename from src/flash.rs rename to hifive1/src/flash.rs diff --git a/src/gpio.rs b/hifive1/src/gpio.rs similarity index 100% rename from src/gpio.rs rename to hifive1/src/gpio.rs diff --git a/src/led.rs b/hifive1/src/led.rs similarity index 100% rename from src/led.rs rename to hifive1/src/led.rs diff --git a/src/lib.rs b/hifive1/src/lib.rs similarity index 100% rename from src/lib.rs rename to hifive1/src/lib.rs diff --git a/src/stdout.rs b/hifive1/src/stdout.rs similarity index 100% rename from src/stdout.rs rename to hifive1/src/stdout.rs From e00b007d4736b2de3b5648033698b1c07f184303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 7 Oct 2024 19:20:14 +0200 Subject: [PATCH 315/315] adapt to Cargo workspace --- .github/workflows/changelog.yaml | 10 +++++ .github/workflows/e310x-hal.yaml | 8 ++-- .github/workflows/e310x.yaml | 13 +++--- .github/workflows/hifive1.yaml | 52 ++++++++++++++++++++++ Cargo.toml | 1 + e310x-hal/CHANGELOG.md | 2 +- e310x-hal/Cargo.toml | 2 +- e310x-hal/README.md | 2 +- e310x/CHANGELOG.md | 2 +- e310x/Cargo.toml | 2 +- e310x/README.md | 2 +- hifive1/.github/CODEOWNERS | 1 - hifive1/.github/bors.toml | 10 ----- hifive1/.github/workflows/ci.yaml | 61 -------------------------- hifive1/.github/workflows/rustfmt.yaml | 24 ---------- hifive1/.gitignore | 4 -- hifive1/CHANGELOG.md | 2 + hifive1/CODE_OF_CONDUCT.md | 37 ---------------- hifive1/Cargo.toml | 9 ++-- hifive1/README.md | 2 +- hifive1/src/clock.rs | 6 +-- hifive1/src/flash.rs | 6 +-- hifive1/src/gpio.rs | 12 ++--- hifive1/src/lib.rs | 5 +++ hifive1/src/stdout.rs | 8 ++-- 25 files changed, 107 insertions(+), 176 deletions(-) create mode 100644 .github/workflows/hifive1.yaml delete mode 100644 hifive1/.github/CODEOWNERS delete mode 100644 hifive1/.github/bors.toml delete mode 100644 hifive1/.github/workflows/ci.yaml delete mode 100644 hifive1/.github/workflows/rustfmt.yaml delete mode 100644 hifive1/.gitignore delete mode 100644 hifive1/CODE_OF_CONDUCT.md diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index 61dcc37..3de2072 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -21,6 +21,8 @@ jobs: - 'e310x/**' e310x-hal: - 'e310x-hal/**' + hifive1: + - 'hifive1/**' - name: Check for CHANGELOG.md (e310x) if: steps.changes.outputs['e310x'] == 'true' @@ -37,4 +39,12 @@ jobs: changeLogPath: ./e310x-hal/CHANGELOG.md skipLabels: 'skip changelog' missingUpdateErrorMessage: 'Please add a changelog entry in the e310x-hal/CHANGELOG.md file.' + + - name: Check for CHANGELOG.md (hifive1) + if: steps.changes.outputs['hifive1'] == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: ./hifive1/CHANGELOG.md + skipLabels: 'skip changelog' + missingUpdateErrorMessage: 'Please add a changelog entry in the hifive1/CHANGELOG.md file.' \ No newline at end of file diff --git a/.github/workflows/e310x-hal.yaml b/.github/workflows/e310x-hal.yaml index db7ec55..0ffea09 100644 --- a/.github/workflows/e310x-hal.yaml +++ b/.github/workflows/e310x-hal.yaml @@ -11,8 +11,8 @@ jobs: build-riscv: strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.65.0 - toolchain: [ stable, nightly, 1.65.0 ] + # All generated code should be running on stable now, MRSV is 1.72.0 + toolchain: [ stable, nightly, 1.72.0 ] include: # Nightly is only for reference and allowed to fail - toolchain: nightly @@ -26,9 +26,9 @@ jobs: - name: Install Rust target run: rustup target install riscv32imc-unknown-none-elf - name: Build (no features) - run: cargo build --package e310x-hal --target riscv32imc-unknown-none-elf + run: cargo build --package e310x-hal - name: Build (all features) - run: cargo build --package e310x-hal --target riscv32imc-unknown-none-elf --all-features + run: cargo build --package e310x-hal --all-features # On MacOS and Ubuntu, we at least make sure that the crate builds and links. # On Windows, linking fails when the rt feature is enabled. diff --git a/.github/workflows/e310x.yaml b/.github/workflows/e310x.yaml index 5c110c9..8247a9f 100644 --- a/.github/workflows/e310x.yaml +++ b/.github/workflows/e310x.yaml @@ -11,11 +11,8 @@ jobs: build-riscv: strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.65.0 - toolchain: [ stable, nightly, 1.65.0 ] - target: - - riscv32imc-unknown-none-elf - - riscv32imac-unknown-none-elf # TODO e310x is not a purely IMAC core + # All generated code should be running on stable now, MRSV is 1.72.0 + toolchain: [ stable, nightly, 1.72.0 ] include: # Nightly is only for reference and allowed to fail - toolchain: nightly @@ -27,11 +24,11 @@ jobs: - name: Update Rust toolchain run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - name: Install Rust target - run: rustup target install ${{ matrix.target }} + run: rustup target install riscv32imc-unknown-none-elf - name: Build (no features) - run: cargo build --package e310x --target ${{ matrix.target }} + run: cargo build --package e310x - name: Build (all features) - run: cargo build --package e310x --target ${{ matrix.target }} --all-features + run: cargo build --package e310x --all-features # On MacOS and Ubuntu, we at least make sure that the crate builds and links. # On Windows, linking fails when the rt feature is enabled. diff --git a/.github/workflows/hifive1.yaml b/.github/workflows/hifive1.yaml new file mode 100644 index 0000000..0ff7f13 --- /dev/null +++ b/.github/workflows/hifive1.yaml @@ -0,0 +1,52 @@ +on: + push: + branches: [ master ] + pull_request: + merge_group: + +name: Build check (hifive1) + +jobs: + # We check that the crate builds and links for all the toolchains and targets. + build-riscv: + strategy: + matrix: + # All generated code should be running on stable now, MRSV is 1.72.0 + toolchain: [nightly, stable, 1.72.0] + board: [hifive1, hifive1-revb, redv, lofive, lofive-r1] + include: + # Nightly is only for reference and allowed to fail + - toolchain: nightly + experimental: true + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || false }} + steps: + - uses: actions/checkout@v4 + - name: Update Rust toolchain + run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - name: Install Rust target + run: rustup target install riscv32imc-unknown-none-elf + - name: Build (direct) + run: cargo build --package hifive1 --features board-${{ matrix.board }} + - name: Build (vectored) + run: cargo build --package hifive1 --features board-${{ matrix.board }},virq + + # On MacOS and Ubuntu, we at least make sure that the crate builds and links. + # On Windows, linking fails when the rt feature is enabled. + build-others: + strategy: + matrix: + os: [ macos-latest, ubuntu-latest ] + board: [hifive1, hifive1-revb, redv, lofive, lofive-r1] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Update Rust toolchain + run: rustup update stable && rustup default stable + - name: Rename .cargo/config to .cargo/config.bak to ignore it + run: mv .cargo/config.toml .cargo/config.bak + - name: Build (direct) + run: cargo test --package hifive1 --features board-${{ matrix.board }} + - name: Build (vectored) + run: cargo test --package hifive1 --features board-${{ matrix.board }},virq + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index b29765b..2cdd788 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ resolver = "2" members = [ "e310x", "e310x-hal", + "hifive1", ] diff --git a/e310x-hal/CHANGELOG.md b/e310x-hal/CHANGELOG.md index 2b6dd98..27a341a 100644 --- a/e310x-hal/CHANGELOG.md +++ b/e310x-hal/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Use `portable-atomic` with `zaamo` feature to use native `amo*` operations. - Official target is now `riscv32imc-unknown-none-elf`, as it does not fully support the A extension. - Update `e310x` dependency and adapt code -- Bump MSRV to 1.65.0 (check Cargo.toml) +- Bump MSRV to 1.72.0 to ensure a correct behavior of portable-atomic ## [v0.10.0] - 2023-03-28 diff --git a/e310x-hal/Cargo.toml b/e310x-hal/Cargo.toml index 69b6372..57eaf03 100644 --- a/e310x-hal/Cargo.toml +++ b/e310x-hal/Cargo.toml @@ -8,7 +8,7 @@ description = "HAL for the E310x family of microcontrollers." keywords = ["riscv", "e310", "hal"] license = "ISC" edition = "2021" -rust-version = "1.65" +rust-version = "1.72" [dependencies] embedded-hal = { version = "0.2.6", features = ["unproven"] } diff --git a/e310x-hal/README.md b/e310x-hal/README.md index fe081e8..a3f65bb 100644 --- a/e310x-hal/README.md +++ b/e310x-hal/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.60.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.72.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/e310x/CHANGELOG.md b/e310x/CHANGELOG.md index 6382762..cd31b6c 100644 --- a/e310x/CHANGELOG.md +++ b/e310x/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed -- Bump MSRV to 1.65.0 (check Cargo.toml) +- Bump MSRV to 1.72.0 to ensure a correct behavior of portable-atomic - Regenerate code with `svd2rust` v0.33.4 ## [v0.11.0] diff --git a/e310x/Cargo.toml b/e310x/Cargo.toml index 89d32d8..b73b28f 100644 --- a/e310x/Cargo.toml +++ b/e310x/Cargo.toml @@ -7,7 +7,7 @@ categories = ["embedded", "hardware-support", "no-std"] description = "With svd2rust generated peripherals for Freedom E310 MCU's." keywords = ["riscv", "register", "peripheral"] license = "ISC" -rust-version = "1.65" +rust-version = "1.72" edition = "2021" [dependencies] diff --git a/e310x/README.md b/e310x/README.md index e8a2a96..0411d7f 100644 --- a/e310x/README.md +++ b/e310x/README.md @@ -11,7 +11,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.65.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.72.0 and up. It *might* compile with older versions but that may change in any new patch release. ## Requirements diff --git a/hifive1/.github/CODEOWNERS b/hifive1/.github/CODEOWNERS deleted file mode 100644 index 87f6c03..0000000 --- a/hifive1/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @rust-embedded/riscv \ No newline at end of file diff --git a/hifive1/.github/bors.toml b/hifive1/.github/bors.toml deleted file mode 100644 index ca7d72a..0000000 --- a/hifive1/.github/bors.toml +++ /dev/null @@ -1,10 +0,0 @@ -block_labels = ["needs-decision"] -delete_merged_branches = true -required_approvals = 1 -status = [ - "ci-linux (stable)", - "ci-linux (1.59.0)", - "build-other (macOS-latest)", - "build-other (windows-latest)", - "Rustfmt" -] diff --git a/hifive1/.github/workflows/ci.yaml b/hifive1/.github/workflows/ci.yaml deleted file mode 100644 index 8f219a4..0000000 --- a/hifive1/.github/workflows/ci.yaml +++ /dev/null @@ -1,61 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Continuous integration - -jobs: - ci-linux: - runs-on: ubuntu-20.04 - continue-on-error: ${{ matrix.experimental || false }} - strategy: - matrix: - # All generated code should be running on stable now, MRSV is 1.59.0 - rust: [nightly, stable, 1.59.0] - - include: - # Nightly is only for reference and allowed to fail - - rust: nightly - experimental: true - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - override: true - - name: Install all Rust targets for ${{ matrix.rust }} - run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf - - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} - run: | - cargo check --target riscv32imac-unknown-none-elf --features board-hifive1 - cargo check --target riscv32imac-unknown-none-elf --features board-hifive1-revb - cargo check --target riscv32imac-unknown-none-elf --features board-redv - cargo check --target riscv32imac-unknown-none-elf --features board-lofive - cargo check --target riscv32imac-unknown-none-elf --features board-lofive-r1 - - # On macOS and Windows, we at least make sure that the crate builds and links. - build-other: - strategy: - matrix: - os: - - macOS-latest - - windows-latest - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - name: Build crate for host OS - run: | - cargo build --features board-hifive1 - cargo build --features board-hifive1-revb - cargo build --features board-redv - cargo build --features board-lofive - cargo build --features board-lofive-r1 \ No newline at end of file diff --git a/hifive1/.github/workflows/rustfmt.yaml b/hifive1/.github/workflows/rustfmt.yaml deleted file mode 100644 index 0727384..0000000 --- a/hifive1/.github/workflows/rustfmt.yaml +++ /dev/null @@ -1,24 +0,0 @@ - -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Code formatting check - -jobs: - fmt: - name: Rustfmt - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check \ No newline at end of file diff --git a/hifive1/.gitignore b/hifive1/.gitignore deleted file mode 100644 index becb52e..0000000 --- a/hifive1/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -Cargo.lock -target/ -core -.gdb_history \ No newline at end of file diff --git a/hifive1/CHANGELOG.md b/hifive1/CHANGELOG.md index e229ad8..cc719d5 100644 --- a/hifive1/CHANGELOG.md +++ b/hifive1/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Bump MSRV to 1.72 +- Adapt to new Cargo workspace - Use inline assembly instead of binary blobs for flash ## [v0.12.0] - 2023-03-28 diff --git a/hifive1/CODE_OF_CONDUCT.md b/hifive1/CODE_OF_CONDUCT.md deleted file mode 100644 index fccadf9..0000000 --- a/hifive1/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,37 +0,0 @@ -# The Rust Code of Conduct - -## Conduct - -**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team) - -* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. -* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. -* Please be kind and courteous. There's no need to be mean or rude. -* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. -* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. -* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. -* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. -* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. - -## Moderation - -These are the policies for upholding our community's standards of conduct. - -1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) -2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. -3. Moderators will first respond to such remarks with a warning. -4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. -5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. -6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. -7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. -8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. - -In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. - -And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. - -The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org). - -*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* - -[team]: https://github.com/rust-embedded/wg#the-riscv-team diff --git a/hifive1/Cargo.toml b/hifive1/Cargo.toml index d875ffd..efa0546 100644 --- a/hifive1/Cargo.toml +++ b/hifive1/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "hifive1" -version = "0.12.0" +version = "0.13.0" repository = "https://github.com/riscv-rust/hifive1" authors = ["David Craven "] categories = ["embedded", "hardware-support", "no-std"] description = "Board support crate for HiFive1 and LoFive boards" keywords = ["riscv", "register", "peripheral"] license = "ISC" -edition = "2018" -rust-version = "1.59" +edition = "2021" +rust-version = "1.72" [dependencies] -e310x-hal = "0.11.0" +e310x-hal = { path = "../e310x-hal", version = "0.11.0" } embedded-hal = "0.2.7" riscv = "0.10.1" nb = "1.0.0" @@ -22,6 +22,7 @@ board-hifive1-revb = ["e310x-hal/g002"] board-redv = ["e310x-hal/g002"] board-lofive = [] board-lofive-r1 = ["e310x-hal/g002"] +virq = ["e310x-hal/virq"] [package.metadata.docs.rs] features = ['board-hifive1-revb'] diff --git a/hifive1/README.md b/hifive1/README.md index a734eb5..a6454d3 100644 --- a/hifive1/README.md +++ b/hifive1/README.md @@ -18,7 +18,7 @@ ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.72.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/hifive1/src/clock.rs b/hifive1/src/clock.rs index 05bd348..d91867a 100644 --- a/hifive1/src/clock.rs +++ b/hifive1/src/clock.rs @@ -2,7 +2,7 @@ use e310x_hal::{ clock::{AonExt, Clocks, PrciExt}, - e310x::{AONCLK, PRCI}, + e310x::{Aonclk, Prci}, time::Hertz, }; @@ -15,7 +15,7 @@ use e310x_hal::{ /// /// For HiFive1 and HiFive1 Rev B boards external oscillators are enabled for /// both high-frequency and low-frequency clocks. -pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { +pub fn configure(prci: Prci, aonclk: Aonclk, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); let coreclk = coreclk .use_external(Hertz(16_000_000)) @@ -32,7 +32,7 @@ pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { /// /// For the LoFive and LoFive R1 boards, external oscillator is enabled for /// high-frequency clock. For low-frequency clock internal oscillator is used. -pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { +pub fn configure(prci: Prci, aonclk: Aonclk, target_coreclk: Hertz) -> Clocks { let coreclk = prci.constrain(); let coreclk = coreclk .use_external(Hertz(16_000_000)) diff --git a/hifive1/src/flash.rs b/hifive1/src/flash.rs index 4208379..71c2992 100644 --- a/hifive1/src/flash.rs +++ b/hifive1/src/flash.rs @@ -1,7 +1,7 @@ //! On-board SPI Flash use e310x_hal::clock::Clocks; -use e310x_hal::e310x::QSPI0; +use e310x_hal::e310x::Qspi0; #[cfg(target_arch = "riscv32")] core::arch::global_asm!( @@ -55,7 +55,7 @@ core::arch::global_asm!( /// Configure SPI Flash interface to maximum supported speed #[inline(always)] -pub fn configure_spi_flash(qspi: &QSPI0, clocks: &Clocks) { +pub fn configure_spi_flash(qspi: &Qspi0, clocks: &Clocks) { unsafe { extern "C" { fn _setup_is25lp(dummy8: bool); @@ -67,5 +67,5 @@ pub fn configure_spi_flash(qspi: &QSPI0, clocks: &Clocks) { _setup_is25lp(true) } } - qspi.sckdiv.modify(|_, w| unsafe { w.div().bits(0) }); + qspi.sckdiv().modify(|_, w| unsafe { w.div().bits(0) }); } diff --git a/hifive1/src/gpio.rs b/hifive1/src/gpio.rs index 4ba26e8..abb2d74 100644 --- a/hifive1/src/gpio.rs +++ b/hifive1/src/gpio.rs @@ -12,8 +12,8 @@ /// /// # Example /// -/// ``` -/// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 +/// ```ignore +/// let mosi = hifive1::pin!(gpio, spi0_mosi); // gpio.pin3 /// ``` /// #[macro_export] @@ -143,8 +143,8 @@ macro_rules! pin { /// /// # Example /// -/// ``` -/// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 +/// ```ignore +/// let mosi = hifive1::pin!(gpio, spi0_mosi); // gpio.pin3 /// ``` /// #[macro_export] @@ -268,8 +268,8 @@ macro_rules! pin { /// /// # Example /// -/// ``` -/// let (mosi, miso, sck, cs) = pins!(gpio, (spi0_mosi, spi0_miso, spi0_sck, spi0_ss0)); +/// ```ignore +/// let (mosi, miso, sck, cs) = hifive1::pins!(gpio, (spi0_mosi, spi0_miso, spi0_sck, spi0_ss0)); /// // (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2) /// ``` /// diff --git a/hifive1/src/lib.rs b/hifive1/src/lib.rs index 9ed422b..f05de91 100644 --- a/hifive1/src/lib.rs +++ b/hifive1/src/lib.rs @@ -25,4 +25,9 @@ pub mod stdout; pub use stdout::configure as configure_stdout; #[doc(hidden)] +#[cfg(any( + feature = "board-hifive1", + feature = "board-hifive1-revb", + feature = "board-redv" +))] pub mod gpio; diff --git a/hifive1/src/stdout.rs b/hifive1/src/stdout.rs index 829cbbd..59be531 100644 --- a/hifive1/src/stdout.rs +++ b/hifive1/src/stdout.rs @@ -3,7 +3,7 @@ use core::fmt; use e310x_hal::{ clock::Clocks, - e310x::UART0, + e310x::Uart0, gpio::gpio0::{Pin16, Pin17}, prelude::*, serial::{Rx, Serial, Tx}, @@ -14,7 +14,7 @@ use riscv::interrupt; static mut STDOUT: Option = None; -struct SerialWrapper(Tx); +struct SerialWrapper(Tx); impl core::fmt::Write for SerialWrapper { fn write_str(&mut self, s: &str) -> fmt::Result { @@ -39,12 +39,12 @@ impl core::fmt::Write for SerialWrapper { /// Configures stdout pub fn configure( - uart: UART0, + uart: Uart0, tx: Pin17, rx: Pin16, baud_rate: Bps, clocks: Clocks, -) -> Rx { +) -> Rx { let tx = tx.into_iof0(); let rx = rx.into_iof0(); let serial = Serial::new(uart, (tx, rx), baud_rate, clocks);