├── .github ├── CODEOWNERS ├── bors.toml └── workflows │ ├── ci.yaml │ └── rustfmt.yaml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── README.md ├── assemble.sh ├── bin └── flash.a ├── build.rs ├── flash.S ├── hifive1-link.x ├── memory-hifive1-revb.x ├── memory-hifive1.x ├── memory-lofive-r1.x └── src ├── clock.rs ├── flash.rs ├── gpio.rs ├── led.rs ├── lib.rs └── stdout.rs /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @rust-embedded/riscv -------------------------------------------------------------------------------- /.github/bors.toml: -------------------------------------------------------------------------------- 1 | block_labels = ["needs-decision"] 2 | delete_merged_branches = true 3 | required_approvals = 1 4 | status = [ 5 | "ci-linux (stable)", 6 | "ci-linux (1.59.0)", 7 | "build-other (macOS-latest)", 8 | "build-other (windows-latest)", 9 | "Rustfmt" 10 | ] 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Continuous integration 7 | 8 | jobs: 9 | ci-linux: 10 | runs-on: ubuntu-20.04 11 | continue-on-error: ${{ matrix.experimental || false }} 12 | strategy: 13 | matrix: 14 | # All generated code should be running on stable now, MRSV is 1.59.0 15 | rust: [nightly, stable, 1.59.0] 16 | 17 | include: 18 | # Nightly is only for reference and allowed to fail 19 | - rust: nightly 20 | experimental: true 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: ${{ matrix.rust }} 28 | override: true 29 | - name: Install all Rust targets for ${{ matrix.rust }} 30 | run: rustup target install --toolchain=${{ matrix.rust }} x86_64-unknown-linux-gnu riscv32imac-unknown-none-elf riscv64imac-unknown-none-elf riscv64gc-unknown-none-elf 31 | - name: Run CI script for riscv32imac-unknown-none-elf under ${{ matrix.rust }} 32 | run: | 33 | cargo check --target riscv32imac-unknown-none-elf --features board-hifive1 34 | cargo check --target riscv32imac-unknown-none-elf --features board-hifive1-revb 35 | cargo check --target riscv32imac-unknown-none-elf --features board-redv 36 | cargo check --target riscv32imac-unknown-none-elf --features board-lofive 37 | cargo check --target riscv32imac-unknown-none-elf --features board-lofive-r1 38 | 39 | # On macOS and Windows, we at least make sure that the crate builds and links. 40 | build-other: 41 | strategy: 42 | matrix: 43 | os: 44 | - macOS-latest 45 | - windows-latest 46 | runs-on: ${{ matrix.os }} 47 | 48 | steps: 49 | - uses: actions/checkout@v2 50 | - uses: actions-rs/toolchain@v1 51 | with: 52 | profile: minimal 53 | toolchain: stable 54 | override: true 55 | - name: Build crate for host OS 56 | run: | 57 | cargo build --features board-hifive1 58 | cargo build --features board-hifive1-revb 59 | cargo build --features board-redv 60 | cargo build --features board-lofive 61 | cargo build --features board-lofive-r1 -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yaml: -------------------------------------------------------------------------------- 1 | 2 | on: 3 | push: 4 | branches: [ staging, trying, master ] 5 | pull_request: 6 | 7 | name: Code formatting check 8 | 9 | jobs: 10 | fmt: 11 | name: Rustfmt 12 | runs-on: ubuntu-20.04 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: stable 19 | override: true 20 | components: rustfmt 21 | - uses: actions-rs/cargo@v1 22 | with: 23 | command: fmt 24 | args: --all -- --check -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | core 4 | .gdb_history -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | env: 4 | - TARGET=x86_64-unknown-linux-gnu 5 | - TARGET=riscv32imac-unknown-none-elf 6 | 7 | rust: 8 | - nightly 9 | - stable 10 | 11 | if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master) 12 | 13 | 14 | install: 15 | - ci/install.sh 16 | 17 | script: 18 | - ci/script.sh 19 | 20 | 21 | cache: cargo 22 | 23 | branches: 24 | only: 25 | - master 26 | - staging 27 | - trying 28 | 29 | notifications: 30 | email: 31 | on_success: never 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | ## [Unreleased] 9 | 10 | ## [v0.12.0] - 2023-03-28 11 | - Update e310x-hal to v0.11 with new svd2rust generated code 12 | 13 | ## [v0.11.0] - 2023-03-03 14 | 15 | ### Changed 16 | - Updated riscv dependency to v0.10 with interrupt/critical section changes 17 | 18 | ## [v0.10.0] - 2021-07-15 19 | 20 | ### Added 21 | 22 | - Added [SparkFun Red-V RedBoard](https://www.sparkfun.com/products/15594)` support 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # The Rust Code of Conduct 2 | 3 | ## Conduct 4 | 5 | **Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team) 6 | 7 | * 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. 8 | * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. 9 | * Please be kind and courteous. There's no need to be mean or rude. 10 | * 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. 11 | * 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. 12 | * 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. 13 | * 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. 14 | * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. 15 | 16 | ## Moderation 17 | 18 | These are the policies for upholding our community's standards of conduct. 19 | 20 | 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.) 21 | 2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 22 | 3. Moderators will first respond to such remarks with a warning. 23 | 4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. 24 | 5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 25 | 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. 26 | 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. 27 | 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. 28 | 29 | 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. 30 | 31 | 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. 32 | 33 | 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). 34 | 35 | *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/).* 36 | 37 | [team]: https://github.com/rust-embedded/wg#the-riscv-team 38 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hifive1" 3 | version = "0.12.0" 4 | repository = "https://github.com/riscv-rust/hifive1" 5 | authors = ["David Craven "] 6 | categories = ["embedded", "hardware-support", "no-std"] 7 | description = "Board support crate for HiFive1 and LoFive boards" 8 | keywords = ["riscv", "register", "peripheral"] 9 | license = "ISC" 10 | edition = "2018" 11 | rust-version = "1.59" 12 | 13 | [dependencies] 14 | e310x-hal = "0.11.0" 15 | embedded-hal = "0.2.7" 16 | riscv = "0.10.1" 17 | nb = "1.0.0" 18 | 19 | [features] 20 | board-hifive1 = [] 21 | board-hifive1-revb = ["e310x-hal/g002"] 22 | board-redv = ["e310x-hal/g002"] 23 | board-lofive = [] 24 | board-lofive-r1 = ["e310x-hal/g002"] 25 | 26 | [package.metadata.docs.rs] 27 | features = ['board-hifive1-revb'] 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![crates.io](https://img.shields.io/crates/d/hifive1.svg)](https://crates.io/crates/hifive1) 2 | [![crates.io](https://img.shields.io/crates/v/hifive1.svg)](https://crates.io/crates/hifive1) 3 | [![Build Status](https://travis-ci.org/riscv-rust/hifive1.svg?branch=master)](https://travis-ci.org/riscv-rust/hifive1) 4 | 5 | # `hifive1` 6 | 7 | > Board support crate for HiFive1 and LoFive boards 8 | 9 | ## Supported Boards 10 | 11 | * [SiFive Hifive1](https://www.sifive.com/boards/hifive1) - use feature `board-hifive1` 12 | * [SiFive Hifive1 RevB](https://www.sifive.com/boards/hifive1-rev-b) - use feature `board-hifive1-revb` 13 | * [SparkFun Red-V RedBoard](https://www.sparkfun.com/products/15594) - use feature `board-redv` 14 | * [lofive1](https://github.com/mwelling/lofive) - use feature `board-lofive` 15 | * [lofive1-r1](https://github.com/mwelling/lofive) - use feature `board-lofive-r1` 16 | 17 | ## [Documentation](https://docs.rs/crate/hifive1) 18 | 19 | ## Minimum Supported Rust Version (MSRV) 20 | 21 | This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* 22 | compile with older versions but that may change in any new patch release. 23 | 24 | ## License 25 | 26 | Copyright 2018-2023 [RISC-V team][team] 27 | 28 | Permission to use, copy, modify, and/or distribute this software for any purpose 29 | with or without fee is hereby granted, provided that the above copyright notice 30 | and this permission notice appear in all copies. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 33 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 34 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 35 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 36 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 37 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 38 | THIS SOFTWARE. 39 | 40 | ## Code of Conduct 41 | 42 | Contribution to this crate is organized under the terms of the [Rust Code of 43 | Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises 44 | to intervene to uphold that code of conduct. 45 | 46 | [CoC]: CODE_OF_CONDUCT.md 47 | [team]: https://github.com/rust-embedded/wg#the-risc-v-team 48 | -------------------------------------------------------------------------------- /assemble.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euxo pipefail 4 | 5 | # remove existing blobs because otherwise this will append object files to the old blobs 6 | rm -f bin/*.a 7 | 8 | riscv64-unknown-elf-gcc -ggdb3 -fdebug-prefix-map=$(pwd)=/hifive1 -c -mabi=ilp32 -march=rv32imac flash.S -o bin/flash.o 9 | riscv64-unknown-elf-ar crs bin/flash.a bin/flash.o 10 | 11 | rm bin/flash.o 12 | -------------------------------------------------------------------------------- /bin/flash.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riscv-rust/hifive1/0901b554001b0ea7ca7cde639d22d94310c4f32a/bin/flash.a -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use std::{env, fs}; 3 | 4 | fn main() { 5 | // Put the memory definitions somewhere the linker can find it 6 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 7 | println!("cargo:rustc-link-search={}", out_dir.display()); 8 | 9 | let boards: Vec<_> = env::vars() 10 | .filter_map(|(key, _value)| { 11 | if key.starts_with("CARGO_FEATURE_BOARD") { 12 | Some(key[20..].to_ascii_lowercase()) // Strip 'CARGO_FEATURE_BOARD_' 13 | } else { 14 | None 15 | } 16 | }) 17 | .collect(); 18 | 19 | if boards.is_empty() { 20 | panic!("No board features selected"); 21 | } 22 | if boards.len() > 1 { 23 | panic!("More than one board feature selected: {:?}", boards); 24 | } 25 | 26 | let board = boards.first().unwrap(); 27 | 28 | match board.as_str() { 29 | "hifive1" => { 30 | fs::copy("memory-hifive1.x", out_dir.join("hifive1-memory.x")).unwrap(); 31 | println!("cargo:rerun-if-changed=memory-hifive1.x"); 32 | } 33 | "hifive1_revb" | "redv" => { 34 | fs::copy("memory-hifive1-revb.x", out_dir.join("hifive1-memory.x")).unwrap(); 35 | println!("cargo:rerun-if-changed=memory-hifive1-revb.x"); 36 | } 37 | "lofive" | "lofive_r1" => { 38 | fs::copy("memory-lofive-r1.x", out_dir.join("hifive1-memory.x")).unwrap(); 39 | println!("cargo:rerun-if-changed=memory-lofive-r1.x"); 40 | } 41 | 42 | other => panic!("Unknown board: {}", other), 43 | } 44 | 45 | fs::copy("hifive1-link.x", out_dir.join("hifive1-link.x")).unwrap(); 46 | println!("cargo:rerun-if-changed=hifive1-link.x"); 47 | 48 | // Copy library with flash setup code 49 | let name = env::var("CARGO_PKG_NAME").unwrap(); 50 | fs::copy("bin/flash.a", out_dir.join(format!("lib{}.a", name))).unwrap(); 51 | println!("cargo:rustc-link-lib=static={}", name); 52 | println!("cargo:rerun-if-changed=bin/flash.a"); 53 | } 54 | -------------------------------------------------------------------------------- /flash.S: -------------------------------------------------------------------------------- 1 | .cfi_sections .debug_frame 2 | 3 | .section .data._setup_is25lp 4 | .global _setup_is25lp 5 | .cfi_startproc 6 | _setup_is25lp: 7 | li a1, 0x10014000 // QSPI0 base address 8 | 9 | // Disable mapped region 10 | sw zero,96(a1) // fctrl.en = 0 11 | 12 | // Construct ffmt value for 4 dummy cycles 13 | li a2, 0x00BB1447 14 | 15 | beqz a0, 2f 16 | 17 | // We need to set 8 dummy cycles instead of 4. 18 | // Issue a "Set Read Parameters" command. 19 | 20 | li a0,2 21 | sw a0,24(a1) // csmode = HOLD 22 | li a0,0xC0 23 | sw a0,72(a1) // txdata = 0xC0 24 | li a0,0xF0 25 | sw a0,72(a1) // txdata = 0xF0 26 | sw zero,24(a1) // csmode = AUTO 27 | 28 | // Discard two response bytes 29 | 1: lw a0,76(a1) 30 | bltz a0,1b 31 | 1: lw a0,76(a1) 32 | bltz a0,1b 33 | 34 | addi a2,a2,0x40 // ffmt: 4 -> 8 dummy cycles 35 | 2: 36 | sw a2,100(a1) // Write ffmt 37 | 38 | // Enable mapped region 39 | li a0, 1 40 | sw a0,96(a1) // fctrl.en = 1 41 | ret 42 | 43 | 44 | .cfi_endproc 45 | .size _setup_is25lp, . - _setup_is25lp 46 | -------------------------------------------------------------------------------- /hifive1-link.x: -------------------------------------------------------------------------------- 1 | INCLUDE hifive1-memory.x 2 | INCLUDE link.x 3 | -------------------------------------------------------------------------------- /memory-hifive1-revb.x: -------------------------------------------------------------------------------- 1 | INCLUDE device.x 2 | MEMORY 3 | { 4 | FLASH : ORIGIN = 0x20000000, LENGTH = 4M 5 | } 6 | 7 | REGION_ALIAS("REGION_TEXT", FLASH); 8 | REGION_ALIAS("REGION_RODATA", FLASH); 9 | REGION_ALIAS("REGION_DATA", RAM); 10 | REGION_ALIAS("REGION_BSS", RAM); 11 | REGION_ALIAS("REGION_HEAP", RAM); 12 | REGION_ALIAS("REGION_STACK", RAM); 13 | 14 | /* Skip first 64k allocated for bootloader */ 15 | _stext = 0x20010000; 16 | -------------------------------------------------------------------------------- /memory-hifive1.x: -------------------------------------------------------------------------------- 1 | INCLUDE device.x 2 | MEMORY 3 | { 4 | FLASH : ORIGIN = 0x20000000, LENGTH = 16M 5 | } 6 | 7 | REGION_ALIAS("REGION_TEXT", FLASH); 8 | REGION_ALIAS("REGION_RODATA", FLASH); 9 | REGION_ALIAS("REGION_DATA", RAM); 10 | REGION_ALIAS("REGION_BSS", RAM); 11 | REGION_ALIAS("REGION_HEAP", RAM); 12 | REGION_ALIAS("REGION_STACK", RAM); 13 | 14 | /* Skip first 4M allocated for bootloader */ 15 | _stext = 0x20400000; 16 | -------------------------------------------------------------------------------- /memory-lofive-r1.x: -------------------------------------------------------------------------------- 1 | INCLUDE device.x 2 | MEMORY 3 | { 4 | FLASH : ORIGIN = 0x20000000, LENGTH = 16M 5 | } 6 | 7 | REGION_ALIAS("REGION_TEXT", FLASH); 8 | REGION_ALIAS("REGION_RODATA", FLASH); 9 | REGION_ALIAS("REGION_DATA", RAM); 10 | REGION_ALIAS("REGION_BSS", RAM); 11 | REGION_ALIAS("REGION_HEAP", RAM); 12 | REGION_ALIAS("REGION_STACK", RAM); 13 | 14 | /* Skip first 4M allocated for bootloader */ 15 | _stext = 0x20400000; 16 | -------------------------------------------------------------------------------- /src/clock.rs: -------------------------------------------------------------------------------- 1 | //! Board-specific clock configuration 2 | 3 | use e310x_hal::{ 4 | clock::{AonExt, Clocks, PrciExt}, 5 | e310x::{AONCLK, PRCI}, 6 | time::Hertz, 7 | }; 8 | 9 | #[cfg(any( 10 | feature = "board-hifive1", 11 | feature = "board-hifive1-revb", 12 | feature = "board-redv" 13 | ))] 14 | /// Configures clock generation system. 15 | /// 16 | /// For HiFive1 and HiFive1 Rev B boards external oscillators are enabled for 17 | /// both high-frequency and low-frequency clocks. 18 | pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { 19 | let coreclk = prci.constrain(); 20 | let coreclk = coreclk 21 | .use_external(Hertz(16_000_000)) 22 | .coreclk(target_coreclk); 23 | 24 | let aonclk = aonclk.constrain(); 25 | let aonclk = aonclk.use_external(Hertz(32_768)); 26 | 27 | Clocks::freeze(coreclk, aonclk) 28 | } 29 | 30 | #[cfg(any(feature = "board-lofive", feature = "board-lofive-r1"))] 31 | /// Configures clock generation system. 32 | /// 33 | /// For the LoFive and LoFive R1 boards, external oscillator is enabled for 34 | /// high-frequency clock. For low-frequency clock internal oscillator is used. 35 | pub fn configure(prci: PRCI, aonclk: AONCLK, target_coreclk: Hertz) -> Clocks { 36 | let coreclk = prci.constrain(); 37 | let coreclk = coreclk 38 | .use_external(Hertz(16_000_000)) 39 | .coreclk(target_coreclk); 40 | 41 | let aonclk = aonclk.constrain(); 42 | 43 | Clocks::freeze(coreclk, aonclk) 44 | } 45 | -------------------------------------------------------------------------------- /src/flash.rs: -------------------------------------------------------------------------------- 1 | //! On-board SPI Flash 2 | 3 | use e310x_hal::clock::Clocks; 4 | use e310x_hal::e310x::QSPI0; 5 | 6 | /// Configure SPI Flash interface to maximum supported speed 7 | #[inline(always)] 8 | pub fn configure_spi_flash(qspi: &QSPI0, clocks: &Clocks) { 9 | unsafe { 10 | extern "C" { 11 | fn _setup_is25lp(dummy8: bool); 12 | } 13 | 14 | if clocks.coreclk().0 <= 208_000_000 { 15 | _setup_is25lp(false) 16 | } else { 17 | _setup_is25lp(true) 18 | } 19 | } 20 | qspi.sckdiv.modify(|_, w| unsafe { w.div().bits(0) }); 21 | } 22 | -------------------------------------------------------------------------------- /src/gpio.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 2 | /// 3 | /// Returns single pin for given gpio object mapped accordingly 4 | /// 5 | /// # Mappings 6 | /// 7 | /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) 8 | /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) 9 | /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) 10 | /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 11 | /// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) 12 | /// 13 | /// # Example 14 | /// 15 | /// ``` 16 | /// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 17 | /// ``` 18 | /// 19 | #[macro_export] 20 | macro_rules! pin { 21 | // empty 22 | ($gpio:ident, none) => { 23 | () 24 | }; 25 | // spi 26 | ($gpio:ident, spi0_sck) => { 27 | $gpio.pin5 28 | }; 29 | ($gpio:ident, spi0_mosi) => { 30 | $gpio.pin3 31 | }; 32 | ($gpio:ident, spi0_miso) => { 33 | $gpio.pin4 34 | }; 35 | ($gpio:ident, spi0_ss0) => { 36 | $gpio.pin2 37 | }; 38 | // spi_ss1 is not documented 39 | ($gpio:ident, spi0_ss2) => { 40 | $gpio.pin9 41 | }; 42 | ($gpio:ident, spi0_ss3) => { 43 | $gpio.pin10 44 | }; 45 | // i2c 46 | ($gpio:ident, i2c0_sda) => { 47 | $gpio.pin12 48 | }; 49 | ($gpio:ident, i2c0_scl) => { 50 | $gpio.pin13 51 | }; 52 | // serial 53 | ($gpio:ident, uart0_tx) => { 54 | $gpio.pin17 55 | }; 56 | ($gpio:ident, uart0_rx) => { 57 | $gpio.pin16 58 | }; 59 | // digital/physical 60 | ($gpio:ident, dig0) => { 61 | $gpio.pin16 62 | }; 63 | ($gpio:ident, dig1) => { 64 | $gpio.pin17 65 | }; 66 | ($gpio:ident, dig2) => { 67 | $gpio.pin18 68 | }; 69 | ($gpio:ident, dig3) => { 70 | $gpio.pin19 71 | }; 72 | ($gpio:ident, dig4) => { 73 | $gpio.pin20 74 | }; 75 | ($gpio:ident, dig5) => { 76 | $gpio.pin21 77 | }; 78 | ($gpio:ident, dig6) => { 79 | $gpio.pin22 80 | }; 81 | ($gpio:ident, dig7) => { 82 | $gpio.pin23 83 | }; 84 | ($gpio:ident, dig8) => { 85 | $gpio.pin0 86 | }; 87 | ($gpio:ident, dig9) => { 88 | $gpio.pin1 89 | }; 90 | ($gpio:ident, dig10) => { 91 | $gpio.pin2 92 | }; 93 | ($gpio:ident, dig11) => { 94 | $gpio.pin3 95 | }; 96 | ($gpio:ident, dig12) => { 97 | $gpio.pin4 98 | }; 99 | ($gpio:ident, dig13) => { 100 | $gpio.pin5 101 | }; 102 | ($gpio:ident, dig14) => { 103 | $gpio.pin8 104 | }; // tested 105 | ($gpio:ident, dig15) => { 106 | $gpio.pin9 107 | }; 108 | ($gpio:ident, dig16) => { 109 | $gpio.pin10 110 | }; 111 | ($gpio:ident, dig17) => { 112 | $gpio.pin11 113 | }; 114 | ($gpio:ident, dig18) => { 115 | $gpio.pin12 116 | }; 117 | ($gpio:ident, dig19) => { 118 | $gpio.pin13 119 | }; 120 | // onboard LEDs 121 | ($gpio:ident, led_red) => { 122 | $gpio.pin22 123 | }; 124 | ($gpio:ident, led_green) => { 125 | $gpio.pin19 126 | }; 127 | ($gpio:ident, led_blue) => { 128 | $gpio.pin21 129 | }; 130 | } 131 | 132 | #[cfg(feature = "board-redv")] 133 | /// 134 | /// Returns single pin for given gpio object mapped accordingly 135 | /// 136 | /// # Mappings 137 | /// 138 | /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) 139 | /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) 140 | /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) 141 | /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 142 | /// - `led_` - Internal LED light pins where `` is one of (`red`, `green`, `blue`) 143 | /// 144 | /// # Example 145 | /// 146 | /// ``` 147 | /// let mosi = pin!(gpio, spi0_mosi); // gpio.pin3 148 | /// ``` 149 | /// 150 | #[macro_export] 151 | macro_rules! pin { 152 | // empty 153 | ($gpio:ident, none) => { 154 | () 155 | }; 156 | // spi 157 | ($gpio:ident, spi0_sck) => { 158 | $gpio.pin5 159 | }; 160 | ($gpio:ident, spi0_mosi) => { 161 | $gpio.pin3 162 | }; 163 | ($gpio:ident, spi0_miso) => { 164 | $gpio.pin4 165 | }; 166 | ($gpio:ident, spi0_ss0) => { 167 | $gpio.pin2 168 | }; 169 | // spi_ss1 is not documented 170 | ($gpio:ident, spi0_ss2) => { 171 | $gpio.pin9 172 | }; 173 | ($gpio:ident, spi0_ss3) => { 174 | $gpio.pin10 175 | }; 176 | // i2c 177 | ($gpio:ident, i2c0_sda) => { 178 | $gpio.pin12 179 | }; 180 | ($gpio:ident, i2c0_scl) => { 181 | $gpio.pin13 182 | }; 183 | // serial 184 | ($gpio:ident, uart0_tx) => { 185 | $gpio.pin17 186 | }; 187 | ($gpio:ident, uart0_rx) => { 188 | $gpio.pin16 189 | }; 190 | // digital/physical 191 | ($gpio:ident, dig0) => { 192 | $gpio.pin16 193 | }; 194 | ($gpio:ident, dig1) => { 195 | $gpio.pin17 196 | }; 197 | ($gpio:ident, dig2) => { 198 | $gpio.pin18 199 | }; 200 | ($gpio:ident, dig3) => { 201 | $gpio.pin19 202 | }; 203 | ($gpio:ident, dig4) => { 204 | $gpio.pin20 205 | }; 206 | ($gpio:ident, dig5) => { 207 | $gpio.pin21 208 | }; 209 | ($gpio:ident, dig6) => { 210 | $gpio.pin22 211 | }; 212 | ($gpio:ident, dig7) => { 213 | $gpio.pin23 214 | }; 215 | ($gpio:ident, dig8) => { 216 | $gpio.pin0 217 | }; 218 | ($gpio:ident, dig9) => { 219 | $gpio.pin1 220 | }; 221 | ($gpio:ident, dig10) => { 222 | $gpio.pin2 223 | }; 224 | ($gpio:ident, dig11) => { 225 | $gpio.pin3 226 | }; 227 | ($gpio:ident, dig12) => { 228 | $gpio.pin4 229 | }; 230 | ($gpio:ident, dig13) => { 231 | $gpio.pin5 232 | }; 233 | ($gpio:ident, dig14) => { 234 | $gpio.pin8 235 | }; // tested 236 | ($gpio:ident, dig15) => { 237 | $gpio.pin9 238 | }; 239 | ($gpio:ident, dig16) => { 240 | $gpio.pin10 241 | }; 242 | ($gpio:ident, dig17) => { 243 | $gpio.pin11 244 | }; 245 | ($gpio:ident, dig18) => { 246 | $gpio.pin12 247 | }; 248 | ($gpio:ident, dig19) => { 249 | $gpio.pin13 250 | }; 251 | // onboard LEDs 252 | ($gpio:ident, led_blue) => { 253 | $gpio.pin5 254 | }; 255 | } 256 | 257 | /// 258 | /// Returns tuple of pins for given gpio object mapped accordingly 259 | /// 260 | /// # Mappings 261 | /// 262 | /// - `none` — Returns `()` for empty pin if needed in tuple 263 | /// - `spi0_` — SPI pins where `` is one of (`sck`, `mosi`, `miso`, `ss0`, `ss2`, `ss3`) 264 | /// - `i2c0_` — I2C pins where `` is one of (`sda`, `scl`) 265 | /// - `uart0_` — UART pins where `` is one of (`tx`, `rx`) 266 | /// - `dig#` — Digital/physical pins on the board where `#` is from range 0..19 267 | /// - `led_` - Internal LED light pins `` is one of (`red`, `green`, `blue`) 268 | /// 269 | /// # Example 270 | /// 271 | /// ``` 272 | /// let (mosi, miso, sck, cs) = pins!(gpio, (spi0_mosi, spi0_miso, spi0_sck, spi0_ss0)); 273 | /// // (gpio.pin3, gpio.pin4, gpio.pin5, gpio.pin2) 274 | /// ``` 275 | /// 276 | #[macro_export] 277 | macro_rules! pins { 278 | ( $gpio:ident, ($($name:ident),+) ) => { 279 | ($($crate::pin!($gpio, $name)),+) 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/led.rs: -------------------------------------------------------------------------------- 1 | //! On-board user LEDs 2 | //! 3 | //! Hifive1 (+ revB) 4 | //! - Red = Pin 22 5 | //! - Green = Pin 19 6 | //! - Blue = Pin 21 7 | //! 8 | //! RedV 9 | //! - Blue = Pin 5 10 | 11 | #[cfg(feature = "board-redv")] 12 | use e310x_hal::gpio::gpio0::Pin5; 13 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 14 | use e310x_hal::gpio::gpio0::{Pin19, Pin21, Pin22}; 15 | use e310x_hal::gpio::{Invert, Output, Regular}; 16 | use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; 17 | 18 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 19 | /// Red LED 20 | pub type RED = Pin22>>; 21 | 22 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 23 | /// Green LED 24 | pub type GREEN = Pin19>>; 25 | 26 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 27 | /// Blue LED 28 | pub type BLUE = Pin21>>; 29 | 30 | #[cfg(feature = "board-redv")] 31 | /// Blue LED 32 | pub type BLUE = Pin5>>; 33 | 34 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 35 | /// Returns RED, GREEN and BLUE LEDs. 36 | pub fn rgb(red: Pin22, green: Pin19, blue: Pin21) -> (RED, GREEN, BLUE) { 37 | let red: RED = red.into_inverted_output(); 38 | let green: GREEN = green.into_inverted_output(); 39 | let blue: BLUE = blue.into_inverted_output(); 40 | (red, green, blue) 41 | } 42 | 43 | /// Generic LED 44 | pub trait Led { 45 | /// Turns the LED off 46 | fn off(&mut self); 47 | 48 | /// Turns the LED on 49 | fn on(&mut self); 50 | 51 | /// Toggles the LED state 52 | fn toggle(&mut self); 53 | } 54 | 55 | /// Macro to implement the Led trait for each of the board LEDs 56 | macro_rules! led_impl { 57 | ($($LEDTYPE:ident),+) => { 58 | $( 59 | impl Led for $LEDTYPE { 60 | fn off(&mut self) { 61 | self.set_low().unwrap(); 62 | } 63 | 64 | fn on(&mut self) { 65 | self.set_high().unwrap(); 66 | } 67 | 68 | fn toggle(&mut self) { 69 | ToggleableOutputPin::toggle(self).unwrap(); 70 | } 71 | } 72 | )+ 73 | } 74 | } 75 | 76 | /// Call the macro for each LED 77 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 78 | led_impl!(RED, GREEN); 79 | 80 | led_impl!(BLUE); 81 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Board support crate for HiFive1 and LoFive boards 2 | 3 | #![deny(missing_docs)] 4 | #![no_std] 5 | 6 | pub use e310x_hal as hal; 7 | 8 | pub mod clock; 9 | pub use clock::configure as configure_clocks; 10 | 11 | pub mod flash; 12 | 13 | #[cfg(any( 14 | feature = "board-hifive1", 15 | feature = "board-hifive1-revb", 16 | feature = "board-redv" 17 | ))] 18 | pub mod led; 19 | #[cfg(any(feature = "board-hifive1", feature = "board-hifive1-revb"))] 20 | pub use led::{rgb, Led, BLUE, GREEN, RED}; 21 | #[cfg(feature = "board-redv")] 22 | pub use led::{Led, BLUE}; 23 | 24 | pub mod stdout; 25 | pub use stdout::configure as configure_stdout; 26 | 27 | #[doc(hidden)] 28 | pub mod gpio; 29 | -------------------------------------------------------------------------------- /src/stdout.rs: -------------------------------------------------------------------------------- 1 | //! Stdout based on the UART hooked up to FTDI or J-Link 2 | 3 | use core::fmt; 4 | use e310x_hal::{ 5 | clock::Clocks, 6 | e310x::UART0, 7 | gpio::gpio0::{Pin16, Pin17}, 8 | prelude::*, 9 | serial::{Rx, Serial, Tx}, 10 | time::Bps, 11 | }; 12 | use nb::block; 13 | use riscv::interrupt; 14 | 15 | static mut STDOUT: Option = None; 16 | 17 | struct SerialWrapper(Tx); 18 | 19 | impl core::fmt::Write for SerialWrapper { 20 | fn write_str(&mut self, s: &str) -> fmt::Result { 21 | for byte in s.as_bytes() { 22 | if *byte == b'\n' { 23 | let res = block!(self.0.write(b'\r')); 24 | 25 | if res.is_err() { 26 | return Err(::core::fmt::Error); 27 | } 28 | } 29 | 30 | let res = block!(self.0.write(*byte)); 31 | 32 | if res.is_err() { 33 | return Err(::core::fmt::Error); 34 | } 35 | } 36 | Ok(()) 37 | } 38 | } 39 | 40 | /// Configures stdout 41 | pub fn configure( 42 | uart: UART0, 43 | tx: Pin17, 44 | rx: Pin16, 45 | baud_rate: Bps, 46 | clocks: Clocks, 47 | ) -> Rx { 48 | let tx = tx.into_iof0(); 49 | let rx = rx.into_iof0(); 50 | let serial = Serial::new(uart, (tx, rx), baud_rate, clocks); 51 | let (tx, rx) = serial.split(); 52 | 53 | interrupt::free(|| unsafe { 54 | STDOUT.replace(SerialWrapper(tx)); 55 | }); 56 | rx 57 | } 58 | 59 | /// Writes string to stdout 60 | pub fn write_str(s: &str) { 61 | interrupt::free(|| unsafe { 62 | if let Some(stdout) = STDOUT.as_mut() { 63 | let _ = stdout.write_str(s); 64 | } 65 | }) 66 | } 67 | 68 | /// Writes formatted string to stdout 69 | pub fn write_fmt(args: fmt::Arguments) { 70 | interrupt::free(|| unsafe { 71 | if let Some(stdout) = STDOUT.as_mut() { 72 | let _ = stdout.write_fmt(args); 73 | } 74 | }) 75 | } 76 | 77 | /// Macro for printing to the serial standard output 78 | #[macro_export] 79 | macro_rules! sprint { 80 | ($s:expr) => { 81 | $crate::stdout::write_str($s) 82 | }; 83 | ($($tt:tt)*) => { 84 | $crate::stdout::write_fmt(format_args!($($tt)*)) 85 | }; 86 | } 87 | 88 | /// Macro for printing to the serial standard output, with a newline. 89 | #[macro_export] 90 | macro_rules! sprintln { 91 | () => { 92 | $crate::stdout::write_str("\n") 93 | }; 94 | ($s:expr) => { 95 | $crate::stdout::write_str(concat!($s, "\n")) 96 | }; 97 | ($s:expr, $($tt:tt)*) => { 98 | $crate::stdout::write_fmt(format_args!(concat!($s, "\n"), $($tt)*)) 99 | }; 100 | } 101 | --------------------------------------------------------------------------------