├── .github └── workflows │ ├── clippy-check.yml │ ├── cross-compile.yml │ └── security-audit.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── README.md └── src ├── aes.rs ├── apu.rs ├── cache.rs ├── clint.rs ├── clock.rs ├── dmac.rs ├── fft.rs ├── fpioa.rs ├── gpio.rs ├── gpiohs.rs ├── lib.rs ├── plic.rs ├── serial.rs ├── sha256.rs ├── spi.rs ├── sysctl.rs └── time.rs /.github/workflows/clippy-check.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Clippy Check 3 | 4 | jobs: 5 | clippy_check: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - uses: actions-rs/toolchain@v1 10 | with: 11 | toolchain: nightly 12 | components: clippy 13 | override: true 14 | - uses: actions-rs/clippy-check@v1 15 | with: 16 | token: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.github/workflows/cross-compile.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Cross Compile 3 | 4 | jobs: 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | toolchain: stable 13 | target: riscv64gc-unknown-none-elf 14 | override: true 15 | - uses: actions-rs/cargo@v1 16 | with: 17 | use-cross: true 18 | command: build 19 | args: --target riscv64gc-unknown-none-elf 20 | -------------------------------------------------------------------------------- /.github/workflows/security-audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | jobs: 6 | audit: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - uses: actions-rs/audit-check@v1 11 | with: 12 | token: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea 5 | -------------------------------------------------------------------------------- /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 = "k210-hal" 3 | version = "0.2.0" 4 | authors = ["The RISC-V Team "] 5 | categories = ["embedded", "hardware-support", "no-std"] 6 | description = "Hardware Abstract Layer (HAL) support for K210, dual-core RV64GC SoC" 7 | repository = "https://github.com/riscv-rust/k210-hal" 8 | keywords = ["riscv", "k210", "hal"] 9 | license = "ISC" 10 | edition = "2021" 11 | 12 | [package.metadata.docs.rs] 13 | targets = ["riscv64gc-unknown-none-elf"] 14 | 15 | [dependencies] 16 | embedded-hal = "1.0.0" 17 | embedded-io = "0.6.1" 18 | k210-pac = "0.2.0" 19 | bitflags = "1.3" 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![crates.io](https://img.shields.io/crates/d/k210-hal.svg)](https://crates.io/crates/k210-hal) 2 | [![crates.io](https://img.shields.io/crates/v/k210-hal.svg)](https://crates.io/crates/k210-hal) 3 | [![Build Status](https://travis-ci.org/riscv-rust/k210-hal.svg?branch=master)](https://travis-ci.org/riscv-rust/k210-hal) 4 | 5 | # `k210-hal` 6 | 7 | > Hardware abstract layer (HAL) for K210 chip, a dual RV64GC SoC with hardware 8 | > accelerated AI peripherals. 9 | 10 | This project is developed and maintained by the [RISC-V team][team]. 11 | 12 | ## [Documentation](https://docs.rs/k210-hal) 13 | 14 | ## License 15 | 16 | Copyright 2019 [RISC-V team][team] 17 | 18 | Permission to use, copy, modify, and/or distribute this software for any 19 | purpose with or without fee is hereby granted, provided that the above 20 | copyright notice and this permission notice appear in all copies. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 23 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 24 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 25 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 26 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 27 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 28 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 29 | 30 | ## Code of Conduct 31 | 32 | Contribution to this crate is organized under the terms of the [Rust Code of 33 | Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises 34 | to intervene to uphold that code of conduct. 35 | 36 | [CoC]: CODE_OF_CONDUCT.md 37 | [team]: https://github.com/rust-embedded/wg#the-risc-v-team 38 | -------------------------------------------------------------------------------- /src/aes.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Hardware AES calculator (AES) 2 | use crate::pac::AES; 3 | use core::marker::PhantomData; 4 | 5 | pub struct Aes { 6 | aes: AES, 7 | _mode: PhantomData, 8 | _klen: PhantomData, 9 | } 10 | 11 | pub struct Ecb; 12 | 13 | pub struct Cbc; 14 | 15 | pub struct Gcm; 16 | 17 | pub struct K128; 18 | 19 | pub struct K192; 20 | 21 | pub struct K256; 22 | 23 | #[allow(unused)] // todo: remove 24 | impl Aes { 25 | pub fn ecb128(aes: AES) -> Aes { 26 | todo!() 27 | } 28 | 29 | pub fn ecb192(aes: AES) -> Aes { 30 | todo!() 31 | } 32 | 33 | pub fn ecb256(aes: AES) -> Aes { 34 | todo!() 35 | } 36 | 37 | pub fn cbc128(aes: AES) -> Aes { 38 | todo!() 39 | } 40 | 41 | pub fn cbc192(aes: AES) -> Aes { 42 | todo!() 43 | } 44 | 45 | pub fn cbc256(aes: AES) -> Aes { 46 | todo!() 47 | } 48 | 49 | pub fn gcm128(aes: AES) -> Aes { 50 | todo!() 51 | } 52 | 53 | pub fn gcm192(aes: AES) -> Aes { 54 | todo!() 55 | } 56 | 57 | pub fn gcm256(aes: AES) -> Aes { 58 | todo!() 59 | } 60 | } 61 | 62 | impl Aes { 63 | // todo: clock 64 | pub fn free(self) -> AES { 65 | self.aes 66 | } 67 | } 68 | 69 | #[allow(unused)] // todo: remove 70 | impl Aes { 71 | // entrypt block in-place 72 | pub fn encrypt_block(&self, block: &mut [u8], key: &[u8]) { 73 | todo!() 74 | } 75 | // decrypt block in-place 76 | pub fn decrypt_block(&self, block: &mut [u8], key: &[u8]) { 77 | todo!() 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/apu.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Audio Processor Unit (APU) 2 | -------------------------------------------------------------------------------- /src/cache.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Bypass cache 2 | //! 3 | //! Todo: verify this module! 4 | 5 | use core::slice; 6 | use core::str; 7 | 8 | /// Convert a buffer or a pointer into ones with uncached address. 9 | /// 10 | /// Section 3.4.1, Kendryte K210 Datasheet 11 | pub fn uncached(buf: T) -> T { 12 | buf.uncache() 13 | } 14 | 15 | /// Uncacheable buffer or pointer. 16 | pub trait Uncache { 17 | /// Convert this buffer or pointer to uncached addressed ones 18 | fn uncache(self) -> Self; 19 | } 20 | 21 | impl Uncache for &T { 22 | #[inline] 23 | fn uncache(self) -> Self { 24 | let addr = self as *const T as usize; 25 | assert_addr_cached(addr); 26 | // note(unsafe): safe for source address is safe 27 | unsafe { &*((addr - 0x4000_0000) as *const T) } 28 | } 29 | } 30 | 31 | impl Uncache for &mut T { 32 | #[inline] 33 | fn uncache(self) -> Self { 34 | let addr = self as *mut T as usize; 35 | assert_addr_cached(addr); 36 | // note(unsafe): safe for source address is safe 37 | unsafe { &mut *((addr - 0x4000_0000) as *mut T) } 38 | } 39 | } 40 | 41 | impl Uncache for &[T] { 42 | #[inline] 43 | fn uncache(self) -> Self { 44 | let addr = self.as_ptr() as usize; 45 | assert_addr_cached(addr); 46 | let new_ptr = (addr - 0x4000_0000) as *const T; 47 | // note(unsafe): source address is safe; passing ownership 48 | unsafe { slice::from_raw_parts(new_ptr, self.len()) } 49 | } 50 | } 51 | 52 | impl Uncache for &mut [T] { 53 | #[inline] 54 | fn uncache(self) -> Self { 55 | let addr = self.as_ptr() as usize; 56 | assert_addr_cached(addr); 57 | let new_ptr = (addr - 0x4000_0000) as *mut T; 58 | // note(unsafe): source address is safe; passing ownership 59 | unsafe { slice::from_raw_parts_mut(new_ptr, self.len()) } 60 | } 61 | } 62 | 63 | impl Uncache for &str { 64 | #[inline] 65 | fn uncache(self) -> Self { 66 | let addr = self.as_ptr() as usize; 67 | assert_addr_cached(addr); 68 | let new_ptr = (addr - 0x4000_0000) as *const u8; 69 | // note(unsafe): source address is safe; passing ownership 70 | let slice = unsafe { slice::from_raw_parts(new_ptr, self.len()) }; 71 | // note(unsafe): source slice is guaranteed valid in UTF-8 72 | unsafe { str::from_utf8_unchecked(slice) } 73 | } 74 | } 75 | 76 | impl Uncache for &mut str { 77 | #[inline] 78 | fn uncache(self) -> Self { 79 | let addr = self.as_ptr() as usize; 80 | assert_addr_cached(addr); 81 | let new_ptr = (addr - 0x4000_0000) as *mut u8; 82 | // note(unsafe): source address is safe; passing ownership 83 | let slice = unsafe { slice::from_raw_parts_mut(new_ptr, self.len()) }; 84 | // note(unsafe): source slice is guaranteed valid in UTF-8 85 | unsafe { str::from_utf8_unchecked_mut(slice) } 86 | } 87 | } 88 | 89 | impl Uncache for *const T { 90 | #[inline] 91 | fn uncache(self) -> Self { 92 | assert_addr_cached(self as usize); 93 | (self as usize - 0x4000_0000) as *const T 94 | } 95 | } 96 | 97 | impl Uncache for *mut T { 98 | #[inline] 99 | fn uncache(self) -> Self { 100 | assert_addr_cached(self as usize); 101 | (self as usize - 0x4000_0000) as *mut T 102 | } 103 | } 104 | 105 | #[inline] 106 | fn assert_addr_cached(addr: usize) { 107 | /* 108 | SRAM memory: 0x8000_0000 to 0x805F_FFFF 109 | AI memory: 0x8060_0000 to 0x807F_FFFF 110 | SRAM memory includes two parts: MEM0 and MEM1 111 | MEM0 memory: 0x8000_0000 to 0x803F_FFFF 112 | MEM1 memory: 0x8040_0000 to 0x805F_FFFF 113 | */ 114 | // assure that memory is within SRAM or AI 115 | // todo: should we exclude AI? 116 | assert!((0x8000_0000..0x8080_0000).contains(&addr)); 117 | } 118 | -------------------------------------------------------------------------------- /src/clint.rs: -------------------------------------------------------------------------------- 1 | //! Core Local Interruptor (CLINT) 2 | //! 3 | //! TODO: Should this module designed in a somehow IP-core peripheral create? 4 | 5 | /// mtime register 6 | pub mod mtime { 7 | use crate::pac; 8 | /// Read mtime register. 9 | pub fn read() -> u64 { 10 | unsafe { (*pac::CLINT::ptr()).mtime.read().bits() } 11 | } 12 | } 13 | 14 | /// msip register 15 | pub mod msip { 16 | use crate::pac; 17 | 18 | /// set IPI interrupt flag for one given hart 19 | pub fn set_ipi(hart_id: usize) { 20 | unsafe { (*pac::CLINT::ptr()).msip[hart_id].write(|w| w.bits(1)) } 21 | } 22 | /// clear IPI interrupt flag for one given hart 23 | pub fn clear_ipi(hart_id: usize) { 24 | unsafe { (*pac::CLINT::ptr()).msip[hart_id].write(|w| w.bits(0)) } 25 | } 26 | } 27 | 28 | /// mtimecmp register 29 | pub mod mtimecmp { 30 | use crate::pac; 31 | 32 | /// Read 64-bit mtimecmp register for certain hart id 33 | pub fn read(hart_id: usize) -> u64 { 34 | unsafe { (*pac::CLINT::ptr()).mtimecmp[hart_id].read().bits() } 35 | } 36 | 37 | /// Write 64-bit mtimecmp register for certain hart id 38 | pub fn write(hart_id: usize, bits: u64) { 39 | // Volume II: RISC-V Privileged Architectures V1.10 p.31, figure 3.15 40 | unsafe { (*pac::CLINT::ptr()).mtimecmp[hart_id].write(|w| w.bits(bits)) }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/clock.rs: -------------------------------------------------------------------------------- 1 | //! Clock configuration 2 | //use crate::pac::PRCI; 3 | // use crate::sysctl::ACLK; 4 | use crate::time::Hertz; 5 | 6 | /// Frozen clock frequencies 7 | /// 8 | /// The existence of this value indicates that the clock configuration can no 9 | /// longer be changed. 10 | #[derive(Clone, Copy)] 11 | pub struct Clocks { 12 | pub(crate) aclk: Hertz, 13 | pub(crate) apb0: Hertz, 14 | } 15 | 16 | impl Clocks { 17 | #[doc(hidden)] 18 | pub fn new() -> Self { 19 | /* 20 | [MAIXPY]Pll0:freq:806000000 21 | [MAIXPY]Pll1:freq:398666666 22 | [MAIXPY]Pll2:freq:45066666 23 | [MAIXPY]cpu:freq:403000000 24 | [MAIXPY]kpu:freq:398666666 25 | in freq: 26000000 26 | cpu_freq: 390000000 27 | */ 28 | Self { 29 | aclk: Hertz(390_000_000), 30 | apb0: Hertz(195_000_000), 31 | } 32 | } 33 | 34 | /// Returns CPU frequency 35 | pub fn cpu(&self) -> Hertz { 36 | Hertz(self.aclk.0) 37 | } 38 | 39 | /// Returns APB0 frequency 40 | pub fn apb0(&self) -> Hertz { 41 | self.apb0 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/dmac.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Direct Memory Access Controller (DMAC) 2 | use crate::{pac, sysctl}; 3 | 4 | pub fn dmac_id() -> u64 { 5 | unsafe { (*pac::DMAC::ptr()).id.read().bits() } 6 | } 7 | 8 | pub fn dmac_version() -> u64 { 9 | unsafe { (*pac::DMAC::ptr()).compver.read().bits() } 10 | } 11 | 12 | pub trait DmacExt { 13 | fn configure(self /* sysctl ACLK clock */) -> Dmac; 14 | } 15 | 16 | impl DmacExt for pac::DMAC { 17 | fn configure(self /* sysctl ACLK clock */) -> Dmac { 18 | // enable 19 | sysctl::clk_en_peri().modify(|_, w| w.dma_clk_en().set_bit()); 20 | // todo: reset 21 | Dmac {} // todo 22 | } 23 | } 24 | 25 | pub struct Dmac {} 26 | 27 | // pub struct C0 { 28 | // // todo 29 | // pub async fn poll() { 30 | 31 | // } 32 | // } 33 | -------------------------------------------------------------------------------- /src/fft.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Fast Fourier Transform (FFT) 2 | -------------------------------------------------------------------------------- /src/fpioa.rs: -------------------------------------------------------------------------------- 1 | //! Field Programmable IO Array (FPIOA) 2 | 3 | /* 4 | new design: Split FPIOA into several IO pins (IO0, IO1, .., IO47) 5 | with ownership of IOx struct we may change their functions. 6 | For GPIOs and GPIOHS's we should split them into another GpioXx structs. 7 | 8 | note: other modules do not need to require for ownership of certain IOx struct 9 | for that pins and peripherals are considered separate modules. 10 | If this design results in inconvenience or violent of Rust's ownership role 11 | please fire an issue to tell us. 12 | */ 13 | 14 | use crate::pac::FPIOA; 15 | use crate::sysctl::{self, APB0}; 16 | use core::marker::PhantomData; 17 | 18 | /// FPIOA function 19 | pub trait Function { 20 | const INDEX: u8; 21 | } 22 | 23 | /// Pull direction 24 | #[derive(Copy, Clone)] 25 | pub enum Pull { 26 | /// No pulls 27 | None, 28 | /// Pull down 29 | Down, 30 | /// Pull up 31 | Up, 32 | } 33 | 34 | /// FPIOA I/O Pin 35 | pub trait IoPin { 36 | const INDEX: u8; 37 | 38 | fn set_io_pull(&mut self, pull: Pull) { 39 | unsafe { 40 | let fpioa = &*FPIOA::ptr(); 41 | fpioa.io[Self::INDEX as usize].modify(|_, w| match pull { 42 | Pull::None => w.pu().bit(false).pd().bit(false), 43 | Pull::Down => w.pu().bit(false).pd().bit(true), 44 | Pull::Up => w.pu().bit(true).pd().bit(false), 45 | }); 46 | } 47 | } 48 | } 49 | 50 | /// Marker trait for I/O pin function detection 51 | pub trait Mode {} 52 | 53 | /// Extension trait to split a FPIOA peripheral in independent pins and registers 54 | pub trait FpioaExt { 55 | /// Splits the FPIOA block into independent pins and registers 56 | /// 57 | /// todo: split sysctl into two apb's, then use the APB0 to split Fpioa 58 | fn split(self, apb0: &mut APB0) -> Parts; 59 | } 60 | 61 | /// All I/O pins 62 | macro_rules! def_io_pin { 63 | ($($IoX: ident: ($id: expr, $iox: ident, $func: ident);)+) => { 64 | impl FpioaExt for FPIOA { 65 | fn split(self, apb0: &mut APB0) -> Parts { 66 | // enable APB0 bus 67 | apb0.enable(); 68 | // enable sysctl peripheral 69 | sysctl::clk_en_peri().modify(|_r, w| w.fpioa_clk_en().set_bit()); 70 | // return ownership 71 | Parts { 72 | $( $iox: $IoX { _function: PhantomData }, )+ 73 | } 74 | } 75 | } 76 | /// FPIOA Parts 77 | pub struct Parts { 78 | $( 79 | /// Programmable I/O pin 80 | pub $iox: $IoX<$func>, 81 | )+ 82 | // todo: tie controller Tie (force set high or low as input) 83 | } 84 | pub use io_pins::*; 85 | /// All I/O pins 86 | pub mod io_pins { 87 | use core::marker::PhantomData; 88 | use super::{Function, IoPin, Mode, FUNCTION_DEFAULTS}; 89 | use crate::pac::FPIOA; 90 | 91 | $( 92 | /// Programmable I/O pin 93 | pub struct $IoX { 94 | pub(crate) _function: PhantomData 95 | } 96 | 97 | impl $IoX { 98 | /// Change the programmable I/O pin into given function 99 | /// 100 | /// You may refer to module [functions] for all functions. 101 | /// 102 | /// [functions]: ../functions/index.html 103 | pub fn into_function(self, func: F) -> $IoX { 104 | let _ = func; // note(discard): Zero-sized typestate value 105 | unsafe { (*FPIOA::ptr()).io[$id].write(|w| 106 | w.bits(FUNCTION_DEFAULTS[F::INDEX as usize]) 107 | ) }; 108 | $IoX { _function: PhantomData } 109 | } 110 | } 111 | impl IoPin for $IoX { 112 | const INDEX: u8 = $id; 113 | } 114 | impl Mode for $IoX {} 115 | )+ 116 | } 117 | }; 118 | } 119 | 120 | def_io_pin! { 121 | Io0: (0, io0, JTAG_TCLK); 122 | Io1: (1, io1, JTAG_TDI); 123 | Io2: (2, io2, JTAG_TMS); 124 | Io3: (3, io3, JTAG_TDO); 125 | Io4: (4, io4, UARTHS_RX); 126 | Io5: (5, io5, UARTHS_TX); 127 | Io6: (6, io6, RESV0); // (FLOAT*): no default function 128 | Io7: (7, io7, RESV0); // (FLOAT*): no default function 129 | Io8: (8, io8, GPIO0); 130 | Io9: (9, io9, GPIO1); 131 | Io10: (10, io10, GPIO2); 132 | Io11: (11, io11, GPIO3); 133 | Io12: (12, io12, GPIO4); 134 | Io13: (13, io13, GPIO5); 135 | Io14: (14, io14, GPIO6); 136 | Io15: (15, io15, GPIO7); 137 | Io16: (16, io16, GPIOHS0); 138 | Io17: (17, io17, GPIOHS1); 139 | Io18: (18, io18, GPIOHS2); 140 | Io19: (19, io19, GPIOHS3); 141 | Io20: (20, io20, GPIOHS4); 142 | Io21: (21, io21, GPIOHS5); 143 | Io22: (22, io22, GPIOHS6); 144 | Io23: (23, io23, GPIOHS7); 145 | Io24: (24, io24, GPIOHS8); 146 | Io25: (25, io25, GPIOHS9); 147 | Io26: (26, io26, GPIOHS10); 148 | Io27: (27, io27, GPIOHS11); 149 | Io28: (28, io28, GPIOHS12); 150 | Io29: (29, io29, GPIOHS13); 151 | Io30: (30, io30, GPIOHS14); 152 | Io31: (31, io31, GPIOHS15); 153 | Io32: (32, io32, GPIOHS16); 154 | Io33: (33, io33, GPIOHS17); 155 | Io34: (34, io34, GPIOHS18); 156 | Io35: (35, io35, GPIOHS19); 157 | Io36: (36, io36, GPIOHS20); 158 | Io37: (37, io37, GPIOHS21); 159 | Io38: (38, io38, GPIOHS22); 160 | Io39: (39, io39, GPIOHS23); 161 | Io40: (40, io40, GPIOHS24); 162 | Io41: (41, io41, GPIOHS25); 163 | Io42: (42, io42, GPIOHS26); 164 | Io43: (43, io43, GPIOHS27); 165 | Io44: (44, io44, GPIOHS28); 166 | Io45: (45, io45, GPIOHS29); 167 | Io46: (46, io46, GPIOHS30); 168 | Io47: (47, io47, GPIOHS31); 169 | } 170 | 171 | /** Defaults per function (from Kendryte fpioa.c) */ 172 | #[rustfmt::skip] 173 | static FUNCTION_DEFAULTS: &[u32] = &[ 174 | 0x00900000, 0x00900001, 0x00900002, 0x00001f03, 0x00b03f04, 0x00b03f05, 0x00b03f06, 0x00b03f07, 175 | 0x00b03f08, 0x00b03f09, 0x00b03f0a, 0x00b03f0b, 0x00001f0c, 0x00001f0d, 0x00001f0e, 0x00001f0f, 176 | 0x03900010, 0x00001f11, 0x00900012, 0x00001f13, 0x00900014, 0x00900015, 0x00001f16, 0x00001f17, 177 | 0x00901f18, 0x00901f19, 0x00901f1a, 0x00901f1b, 0x00901f1c, 0x00901f1d, 0x00901f1e, 0x00901f1f, 178 | 0x00901f20, 0x00901f21, 0x00901f22, 0x00901f23, 0x00901f24, 0x00901f25, 0x00901f26, 0x00901f27, 179 | 0x00901f28, 0x00901f29, 0x00901f2a, 0x00901f2b, 0x00901f2c, 0x00901f2d, 0x00901f2e, 0x00901f2f, 180 | 0x00901f30, 0x00901f31, 0x00901f32, 0x00901f33, 0x00901f34, 0x00901f35, 0x00901f36, 0x00901f37, 181 | 0x00901f38, 0x00901f39, 0x00901f3a, 0x00901f3b, 0x00901f3c, 0x00901f3d, 0x00901f3e, 0x00901f3f, 182 | 0x00900040, 0x00001f41, 0x00900042, 0x00001f43, 0x00900044, 0x00001f45, 0x00b03f46, 0x00b03f47, 183 | 0x00b03f48, 0x00b03f49, 0x00b03f4a, 0x00b03f4b, 0x00b03f4c, 0x00b03f4d, 0x00001f4e, 0x00001f4f, 184 | 0x00001f50, 0x00001f51, 0x03900052, 0x00001f53, 0x00b03f54, 0x00900055, 0x00900056, 0x00001f57, 185 | 0x00001f58, 0x00001f59, 0x0090005a, 0x0090005b, 0x0090005c, 0x0090005d, 0x00001f5e, 0x00001f5f, 186 | 0x00001f60, 0x00001f61, 0x00001f62, 0x00001f63, 0x00001f64, 0x00900065, 0x00900066, 0x00900067, 187 | 0x00900068, 0x00001f69, 0x00001f6a, 0x00001f6b, 0x00001f6c, 0x00001f6d, 0x00001f6e, 0x00001f6f, 188 | 0x00900070, 0x00900071, 0x00900072, 0x00900073, 0x00001f74, 0x00001f75, 0x00001f76, 0x00001f77, 189 | 0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, 0x0099107e, 0x0099107f, 190 | 0x00991080, 0x00991081, 0x00991082, 0x00991083, 0x00001f84, 0x00001f85, 0x00001f86, 0x00900087, 191 | 0x00900088, 0x00900089, 0x0090008a, 0x0090008b, 0x0090008c, 0x0090008d, 0x0090008e, 0x0090008f, 192 | 0x00900090, 0x00900091, 0x00993092, 0x00993093, 0x00900094, 0x00900095, 0x00900096, 0x00900097, 193 | 0x00900098, 0x00001f99, 0x00001f9a, 0x00001f9b, 0x00001f9c, 0x00001f9d, 0x00001f9e, 0x00001f9f, 194 | 0x00001fa0, 0x00001fa1, 0x009000a2, 0x009000a3, 0x009000a4, 0x009000a5, 0x009000a6, 0x00001fa7, 195 | 0x00001fa8, 0x00001fa9, 0x00001faa, 0x00001fab, 0x00001fac, 0x00001fad, 0x00001fae, 0x00001faf, 196 | 0x009000b0, 0x009000b1, 0x009000b2, 0x009000b3, 0x009000b4, 0x00001fb5, 0x00001fb6, 0x00001fb7, 197 | 0x00001fb8, 0x00001fb9, 0x00001fba, 0x00001fbb, 0x00001fbc, 0x00001fbd, 0x00001fbe, 0x00001fbf, 198 | 0x00001fc0, 0x00001fc1, 0x00001fc2, 0x00001fc3, 0x00001fc4, 0x00001fc5, 0x00001fc6, 0x00001fc7, 199 | 0x00001fc8, 0x00001fc9, 0x00001fca, 0x00001fcb, 0x00001fcc, 0x00001fcd, 0x00001fce, 0x00001fcf, 200 | 0x00001fd0, 0x00001fd1, 0x00001fd2, 0x00001fd3, 0x00001fd4, 0x009000d5, 0x009000d6, 0x009000d7, 201 | 0x009000d8, 0x009100d9, 0x00991fda, 0x009000db, 0x009000dc, 0x009000dd, 0x000000de, 0x009000df, 202 | 0x00001fe0, 0x00001fe1, 0x00001fe2, 0x00001fe3, 0x00001fe4, 0x00001fe5, 0x00001fe6, 0x00001fe7, 203 | 0x00001fe8, 0x00001fe9, 0x00001fea, 0x00001feb, 0x00001fec, 0x00001fed, 0x00001fee, 0x00001fef, 204 | 0x00001ff0, 0x00001ff1, 0x00001ff2, 0x00001ff3, 0x00001ff4, 0x00001ff5, 0x00001ff6, 0x00001ff7, 205 | 0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, 0x00001ffc, 0x00001ffd, 0x00001ffe, 0x00001fff, 206 | ]; 207 | 208 | pub use functions::*; 209 | 210 | /// All programmable functions 211 | pub mod functions { 212 | use super::Function; 213 | 214 | macro_rules! def_function { 215 | ($($name: ident: ($index: expr, $doc: expr);)+) => { 216 | $( 217 | #[doc = $doc] 218 | #[allow(non_camel_case_types)] 219 | pub struct $name; 220 | 221 | impl Function for $name { 222 | const INDEX: u8 = $index; 223 | } 224 | )+ 225 | }; 226 | } 227 | 228 | def_function! { 229 | JTAG_TCLK: (0, "JTAG Test Clock"); 230 | JTAG_TDI: (1, "JTAG Test Data In"); 231 | JTAG_TMS: (2, "JTAG Test Mode Select"); 232 | JTAG_TDO: (3, "JTAG Test Data Out"); 233 | SPI0_D0: (4, "SPI0 Data 0"); 234 | SPI0_D1: (5, "SPI0 Data 1"); 235 | SPI0_D2: (6, "SPI0 Data 2"); 236 | SPI0_D3: (7, "SPI0 Data 3"); 237 | SPI0_D4: (8, "SPI0 Data 4"); 238 | SPI0_D5: (9, "SPI0 Data 5"); 239 | SPI0_D6: (10, "SPI0 Data 6"); 240 | SPI0_D7: (11, "SPI0 Data 7"); 241 | SPI0_SS0: (12, "SPI0 Chip Select 0"); 242 | SPI0_SS1: (13, "SPI0 Chip Select 1"); 243 | SPI0_SS2: (14, "SPI0 Chip Select 2"); 244 | SPI0_SS3: (15, "SPI0 Chip Select 3"); 245 | SPI0_ARB: (16, "SPI0 Arbitration"); 246 | SPI0_SCLK: (17, "SPI0 Serial Clock"); 247 | UARTHS_RX: (18, "UART High speed Receiver"); 248 | UARTHS_TX: (19, "UART High speed Transmitter"); 249 | RESV6: (20, "Reserved function"); 250 | RESV7: (21, "Reserved function"); 251 | CLK_SPI1: (22, "Clock SPI1"); 252 | CLK_I2C1: (23, "Clock I2C1"); 253 | GPIOHS0: (24, "GPIO High speed 0"); 254 | GPIOHS1: (25, "GPIO High speed 1"); 255 | GPIOHS2: (26, "GPIO High speed 2"); 256 | GPIOHS3: (27, "GPIO High speed 3"); 257 | GPIOHS4: (28, "GPIO High speed 4"); 258 | GPIOHS5: (29, "GPIO High speed 5"); 259 | GPIOHS6: (30, "GPIO High speed 6"); 260 | GPIOHS7: (31, "GPIO High speed 7"); 261 | GPIOHS8: (32, "GPIO High speed 8"); 262 | GPIOHS9: (33, "GPIO High speed 9"); 263 | GPIOHS10: (34, "GPIO High speed 10"); 264 | GPIOHS11: (35, "GPIO High speed 11"); 265 | GPIOHS12: (36, "GPIO High speed 12"); 266 | GPIOHS13: (37, "GPIO High speed 13"); 267 | GPIOHS14: (38, "GPIO High speed 14"); 268 | GPIOHS15: (39, "GPIO High speed 15"); 269 | GPIOHS16: (40, "GPIO High speed 16"); 270 | GPIOHS17: (41, "GPIO High speed 17"); 271 | GPIOHS18: (42, "GPIO High speed 18"); 272 | GPIOHS19: (43, "GPIO High speed 19"); 273 | GPIOHS20: (44, "GPIO High speed 20"); 274 | GPIOHS21: (45, "GPIO High speed 21"); 275 | GPIOHS22: (46, "GPIO High speed 22"); 276 | GPIOHS23: (47, "GPIO High speed 23"); 277 | GPIOHS24: (48, "GPIO High speed 24"); 278 | GPIOHS25: (49, "GPIO High speed 25"); 279 | GPIOHS26: (50, "GPIO High speed 26"); 280 | GPIOHS27: (51, "GPIO High speed 27"); 281 | GPIOHS28: (52, "GPIO High speed 28"); 282 | GPIOHS29: (53, "GPIO High speed 29"); 283 | GPIOHS30: (54, "GPIO High speed 30"); 284 | GPIOHS31: (55, "GPIO High speed 31"); 285 | GPIO0: (56, "GPIO pin 0"); 286 | GPIO1: (57, "GPIO pin 1"); 287 | GPIO2: (58, "GPIO pin 2"); 288 | GPIO3: (59, "GPIO pin 3"); 289 | GPIO4: (60, "GPIO pin 4"); 290 | GPIO5: (61, "GPIO pin 5"); 291 | GPIO6: (62, "GPIO pin 6"); 292 | GPIO7: (63, "GPIO pin 7"); 293 | UART1_RX: (64, "UART1 Receiver"); 294 | UART1_TX: (65, "UART1 Transmitter"); 295 | UART2_RX: (66, "UART2 Receiver"); 296 | UART2_TX: (67, "UART2 Transmitter"); 297 | UART3_RX: (68, "UART3 Receiver"); 298 | UART3_TX: (69, "UART3 Transmitter"); 299 | SPI1_D0: (70, "SPI1 Data 0"); 300 | SPI1_D1: (71, "SPI1 Data 1"); 301 | SPI1_D2: (72, "SPI1 Data 2"); 302 | SPI1_D3: (73, "SPI1 Data 3"); 303 | SPI1_D4: (74, "SPI1 Data 4"); 304 | SPI1_D5: (75, "SPI1 Data 5"); 305 | SPI1_D6: (76, "SPI1 Data 6"); 306 | SPI1_D7: (77, "SPI1 Data 7"); 307 | SPI1_SS0: (78, "SPI1 Chip Select 0"); 308 | SPI1_SS1: (79, "SPI1 Chip Select 1"); 309 | SPI1_SS2: (80, "SPI1 Chip Select 2"); 310 | SPI1_SS3: (81, "SPI1 Chip Select 3"); 311 | SPI1_ARB: (82, "SPI1 Arbitration"); 312 | SPI1_SCLK: (83, "SPI1 Serial Clock"); 313 | SPI_SLAVE_D0: (84, "SPI Slave Data 0"); 314 | SPI_SLAVE_SS: (85, "SPI Slave Select"); 315 | SPI_SLAVE_SCLK: (86, "SPI Slave Serial Clock"); 316 | I2S0_MCLK: (87, "I2S0 Master Clock"); 317 | I2S0_SCLK: (88, "I2S0 Serial Clock(BCLK)"); 318 | I2S0_WS: (89, "I2S0 Word Select(LRCLK)"); 319 | I2S0_IN_D0: (90, "I2S0 Serial Data Input 0"); 320 | I2S0_IN_D1: (91, "I2S0 Serial Data Input 1"); 321 | I2S0_IN_D2: (92, "I2S0 Serial Data Input 2"); 322 | I2S0_IN_D3: (93, "I2S0 Serial Data Input 3"); 323 | I2S0_OUT_D0: (94, "I2S0 Serial Data Output 0"); 324 | I2S0_OUT_D1: (95, "I2S0 Serial Data Output 1"); 325 | I2S0_OUT_D2: (96, "I2S0 Serial Data Output 2"); 326 | I2S0_OUT_D3: (97, "I2S0 Serial Data Output 3"); 327 | I2S1_MCLK: (98, "I2S1 Master Clock"); 328 | I2S1_SCLK: (99, "I2S1 Serial Clock(BCLK)"); 329 | I2S1_WS: (100, "I2S1 Word Select(LRCLK)"); 330 | I2S1_IN_D0: (101, "I2S1 Serial Data Input 0"); 331 | I2S1_IN_D1: (102, "I2S1 Serial Data Input 1"); 332 | I2S1_IN_D2: (103, "I2S1 Serial Data Input 2"); 333 | I2S1_IN_D3: (104, "I2S1 Serial Data Input 3"); 334 | I2S1_OUT_D0: (105, "I2S1 Serial Data Output 0"); 335 | I2S1_OUT_D1: (106, "I2S1 Serial Data Output 1"); 336 | I2S1_OUT_D2: (107, "I2S1 Serial Data Output 2"); 337 | I2S1_OUT_D3: (108, "I2S1 Serial Data Output 3"); 338 | I2S2_MCLK: (109, "I2S2 Master Clock"); 339 | I2S2_SCLK: (110, "I2S2 Serial Clock(BCLK)"); 340 | I2S2_WS: (111, "I2S2 Word Select(LRCLK)"); 341 | I2S2_IN_D0: (112, "I2S2 Serial Data Input 0"); 342 | I2S2_IN_D1: (113, "I2S2 Serial Data Input 1"); 343 | I2S2_IN_D2: (114, "I2S2 Serial Data Input 2"); 344 | I2S2_IN_D3: (115, "I2S2 Serial Data Input 3"); 345 | I2S2_OUT_D0: (116, "I2S2 Serial Data Output 0"); 346 | I2S2_OUT_D1: (117, "I2S2 Serial Data Output 1"); 347 | I2S2_OUT_D2: (118, "I2S2 Serial Data Output 2"); 348 | I2S2_OUT_D3: (119, "I2S2 Serial Data Output 3"); 349 | RESV0: (120, "Reserved function"); 350 | RESV1: (121, "Reserved function"); 351 | RESV2: (122, "Reserved function"); 352 | RESV3: (123, "Reserved function"); 353 | RESV4: (124, "Reserved function"); 354 | RESV5: (125, "Reserved function"); 355 | I2C0_SCLK: (126, "I2C0 Serial Clock"); 356 | I2C0_SDA: (127, "I2C0 Serial Data"); 357 | I2C1_SCLK: (128, "I2C1 Serial Clock"); 358 | I2C1_SDA: (129, "I2C1 Serial Data"); 359 | I2C2_SCLK: (130, "I2C2 Serial Clock"); 360 | I2C2_SDA: (131, "I2C2 Serial Data"); 361 | CMOS_XCLK: (132, "DVP System Clock"); 362 | CMOS_RST: (133, "DVP System Reset"); 363 | CMOS_PWDN: (134, "DVP Power Down Mode"); 364 | CMOS_VSYNC: (135, "DVP Vertical Sync"); 365 | CMOS_HREF: (136, "DVP Horizontal Reference output"); 366 | CMOS_PCLK: (137, "Pixel Clock"); 367 | CMOS_D0: (138, "Data Bit 0"); 368 | CMOS_D1: (139, "Data Bit 1"); 369 | CMOS_D2: (140, "Data Bit 2"); 370 | CMOS_D3: (141, "Data Bit 3"); 371 | CMOS_D4: (142, "Data Bit 4"); 372 | CMOS_D5: (143, "Data Bit 5"); 373 | CMOS_D6: (144, "Data Bit 6"); 374 | CMOS_D7: (145, "Data Bit 7"); 375 | SCCB_SCLK: (146, "SCCB Serial Clock"); 376 | SCCB_SDA: (147, "SCCB Serial Data"); 377 | UART1_CTS: (148, "UART1 Clear To Send"); 378 | UART1_DSR: (149, "UART1 Data Set Ready"); 379 | UART1_DCD: (150, "UART1 Data Carrier Detect"); 380 | UART1_RI: (151, "UART1 Ring Indicator"); 381 | UART1_SIR_IN: (152, "UART1 Serial Infrared Input"); 382 | UART1_DTR: (153, "UART1 Data Terminal Ready"); 383 | UART1_RTS: (154, "UART1 Request To Send"); 384 | UART1_OUT2: (155, "UART1 User-designated Output 2"); 385 | UART1_OUT1: (156, "UART1 User-designated Output 1"); 386 | UART1_SIR_OUT: (157, "UART1 Serial Infrared Output"); 387 | UART1_BAUD: (158, "UART1 Transmit Clock Output"); 388 | UART1_RE: (159, "UART1 Receiver Output Enable"); 389 | UART1_DE: (160, "UART1 Driver Output Enable"); 390 | UART1_RS485_EN: (161, "UART1 RS485 Enable"); 391 | UART2_CTS: (162, "UART2 Clear To Send"); 392 | UART2_DSR: (163, "UART2 Data Set Ready"); 393 | UART2_DCD: (164, "UART2 Data Carrier Detect"); 394 | UART2_RI: (165, "UART2 Ring Indicator"); 395 | UART2_SIR_IN: (166, "UART2 Serial Infrared Input"); 396 | UART2_DTR: (167, "UART2 Data Terminal Ready"); 397 | UART2_RTS: (168, "UART2 Request To Send"); 398 | UART2_OUT2: (169, "UART2 User-designated Output 2"); 399 | UART2_OUT1: (170, "UART2 User-designated Output 1"); 400 | UART2_SIR_OUT: (171, "UART2 Serial Infrared Output"); 401 | UART2_BAUD: (172, "UART2 Transmit Clock Output"); 402 | UART2_RE: (173, "UART2 Receiver Output Enable"); 403 | UART2_DE: (174, "UART2 Driver Output Enable"); 404 | UART2_RS485_EN: (175, "UART2 RS485 Enable"); 405 | UART3_CTS: (176, "UART3 Clear To Send"); 406 | UART3_DSR: (177, "UART3 Data Set Ready"); 407 | UART3_DCD: (178, "UART3 Data Carrier Detect"); 408 | UART3_RI: (179, "UART3 Ring Indicator"); 409 | UART3_SIR_IN: (180, "UART3 Serial Infrared Input"); 410 | UART3_DTR: (181, "UART3 Data Terminal Ready"); 411 | UART3_RTS: (182, "UART3 Request To Send"); 412 | UART3_OUT2: (183, "UART3 User-designated Output 2"); 413 | UART3_OUT1: (184, "UART3 User-designated Output 1"); 414 | UART3_SIR_OUT: (185, "UART3 Serial Infrared Output"); 415 | UART3_BAUD: (186, "UART3 Transmit Clock Output"); 416 | UART3_RE: (187, "UART3 Receiver Output Enable"); 417 | UART3_DE: (188, "UART3 Driver Output Enable"); 418 | UART3_RS485_EN: (189, "UART3 RS485 Enable"); 419 | TIMER0_TOGGLE1: (190, "TIMER0 Toggle Output 1"); 420 | TIMER0_TOGGLE2: (191, "TIMER0 Toggle Output 2"); 421 | TIMER0_TOGGLE3: (192, "TIMER0 Toggle Output 3"); 422 | TIMER0_TOGGLE4: (193, "TIMER0 Toggle Output 4"); 423 | TIMER1_TOGGLE1: (194, "TIMER1 Toggle Output 1"); 424 | TIMER1_TOGGLE2: (195, "TIMER1 Toggle Output 2"); 425 | TIMER1_TOGGLE3: (196, "TIMER1 Toggle Output 3"); 426 | TIMER1_TOGGLE4: (197, "TIMER1 Toggle Output 4"); 427 | TIMER2_TOGGLE1: (198, "TIMER2 Toggle Output 1"); 428 | TIMER2_TOGGLE2: (199, "TIMER2 Toggle Output 2"); 429 | TIMER2_TOGGLE3: (200, "TIMER2 Toggle Output 3"); 430 | TIMER2_TOGGLE4: (201, "TIMER2 Toggle Output 4"); 431 | CLK_SPI2: (202, "Clock SPI2"); 432 | CLK_I2C2: (203, "Clock I2C2"); 433 | INTERNAL0: (204, "Internal function signal 0"); 434 | INTERNAL1: (205, "Internal function signal 1"); 435 | INTERNAL2: (206, "Internal function signal 2"); 436 | INTERNAL3: (207, "Internal function signal 3"); 437 | INTERNAL4: (208, "Internal function signal 4"); 438 | INTERNAL5: (209, "Internal function signal 5"); 439 | INTERNAL6: (210, "Internal function signal 6"); 440 | INTERNAL7: (211, "Internal function signal 7"); 441 | INTERNAL8: (212, "Internal function signal 8"); 442 | INTERNAL9: (213, "Internal function signal 9"); 443 | INTERNAL10: (214, "Internal function signal 10"); 444 | INTERNAL11: (215, "Internal function signal 11"); 445 | INTERNAL12: (216, "Internal function signal 12"); 446 | INTERNAL13: (217, "Internal function signal 13"); 447 | INTERNAL14: (218, "Internal function signal 14"); 448 | INTERNAL15: (219, "Internal function signal 15"); 449 | INTERNAL16: (220, "Internal function signal 16"); 450 | INTERNAL17: (221, "Internal function signal 17"); 451 | CONSTANT: (222, "Constant function"); 452 | INTERNAL18: (223, "Internal function signal 18"); 453 | DEBUG0: (224, "Debug function 0"); 454 | DEBUG1: (225, "Debug function 1"); 455 | DEBUG2: (226, "Debug function 2"); 456 | DEBUG3: (227, "Debug function 3"); 457 | DEBUG4: (228, "Debug function 4"); 458 | DEBUG5: (229, "Debug function 5"); 459 | DEBUG6: (230, "Debug function 6"); 460 | DEBUG7: (231, "Debug function 7"); 461 | DEBUG8: (232, "Debug function 8"); 462 | DEBUG9: (233, "Debug function 9"); 463 | DEBUG10: (234, "Debug function 10"); 464 | DEBUG11: (235, "Debug function 11"); 465 | DEBUG12: (236, "Debug function 12"); 466 | DEBUG13: (237, "Debug function 13"); 467 | DEBUG14: (238, "Debug function 14"); 468 | DEBUG15: (239, "Debug function 15"); 469 | DEBUG16: (240, "Debug function 16"); 470 | DEBUG17: (241, "Debug function 17"); 471 | DEBUG18: (242, "Debug function 18"); 472 | DEBUG19: (243, "Debug function 19"); 473 | DEBUG20: (244, "Debug function 20"); 474 | DEBUG21: (245, "Debug function 21"); 475 | DEBUG22: (246, "Debug function 22"); 476 | DEBUG23: (247, "Debug function 23"); 477 | DEBUG24: (248, "Debug function 24"); 478 | DEBUG25: (249, "Debug function 25"); 479 | DEBUG26: (250, "Debug function 26"); 480 | DEBUG27: (251, "Debug function 27"); 481 | DEBUG28: (252, "Debug function 28"); 482 | DEBUG29: (253, "Debug function 29"); 483 | DEBUG30: (254, "Debug function 30"); 484 | DEBUG31: (255, "Debug function 31"); 485 | } 486 | } 487 | -------------------------------------------------------------------------------- /src/gpio.rs: -------------------------------------------------------------------------------- 1 | //! General Purpose Input/Output (GPIO) 2 | 3 | use crate::bit_utils::{u32_bit_is_clear, u32_bit_is_set, u32_set_bit}; 4 | use crate::fpioa::{IoPin, Mode, Pull}; 5 | use crate::pac; 6 | use crate::sysctl::{self, APB0}; 7 | use core::marker::PhantomData; 8 | use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; 9 | 10 | /// Extension trait to split a GPIO peripheral into independent pins 11 | pub trait GpioExt { 12 | /// Split the GPIO peripheral into parts 13 | fn split(self, apb0: &mut APB0) -> Parts; 14 | } 15 | 16 | macro_rules! def_gpio_pins { 17 | ($($GPIOX: ident: ($num: expr, $gpiox: ident, $func: ident);)+) => { 18 | 19 | impl GpioExt for pac::GPIO { 20 | #[inline] 21 | fn split(self, apb0: &mut APB0) -> Parts { 22 | // enable APB0 bus 23 | apb0.enable(); 24 | // enable sysctl peripheral 25 | sysctl::clk_en_peri().modify(|_r, w| w.gpio_clk_en().set_bit()); 26 | // return ownership 27 | Parts { 28 | $( $gpiox: $GPIOX { _ownership: () }, )+ 29 | } 30 | } 31 | } 32 | 33 | /// GPIO peripheral parts 34 | pub struct Parts { 35 | $( 36 | /// GPIO pin 37 | pub $gpiox: $GPIOX, 38 | )+ 39 | } 40 | 41 | pub use gpio_pins::*; 42 | 43 | /// All GPIO pins 44 | pub mod gpio_pins { 45 | use super::GpioIndex; 46 | $( 47 | /// GPIO pin 48 | pub struct $GPIOX { 49 | pub(crate) _ownership: () 50 | } 51 | 52 | impl GpioIndex for $GPIOX { 53 | type FUNC = crate::fpioa::functions::$func; 54 | const INDEX: u8 = $num; 55 | } 56 | )+ 57 | } 58 | }; 59 | } 60 | 61 | def_gpio_pins! { 62 | GPIO0: (0, gpio0, GPIO0); 63 | GPIO1: (1, gpio1, GPIO1); 64 | GPIO2: (2, gpio2, GPIO2); 65 | GPIO3: (3, gpio3, GPIO3); 66 | GPIO4: (4, gpio4, GPIO4); 67 | GPIO5: (5, gpio5, GPIO5); 68 | GPIO6: (6, gpio6, GPIO6); 69 | GPIO7: (7, gpio7, GPIO7); 70 | } 71 | 72 | /// GPIO Index 73 | pub trait GpioIndex { 74 | type FUNC; 75 | const INDEX: u8; 76 | } 77 | 78 | /// Unknown mode (type state) 79 | pub struct Unknown; 80 | 81 | /// Input mode (type state) 82 | pub struct Input(MODE); 83 | 84 | /// Floating input (type state) 85 | pub struct Floating; 86 | 87 | /// Pull down input (type state) 88 | pub struct PullDown; 89 | 90 | /// Pull up input (type state) 91 | pub struct PullUp; 92 | 93 | /// Output mode (type state) 94 | pub struct Output; 95 | 96 | /// Marker trait for active states 97 | pub trait Active {} 98 | 99 | impl Active for Unknown {} 100 | 101 | impl Active for Input {} 102 | 103 | impl Active for Input {} 104 | 105 | impl Active for Input {} 106 | 107 | impl Active for Output {} 108 | 109 | /// GPIO wrapper struct 110 | pub struct Gpio { 111 | gpio: GPIO, 112 | pin: PIN, 113 | _mode: PhantomData, 114 | } 115 | 116 | impl> Gpio { 117 | #[inline] 118 | pub fn new(gpio: GPIO, pin: PIN) -> Gpio { 119 | Gpio { 120 | gpio, 121 | pin, 122 | _mode: PhantomData, 123 | } 124 | } 125 | } 126 | 127 | impl Gpio { 128 | #[inline] 129 | pub fn free(self) -> (GPIO, PIN) { 130 | (self.gpio, self.pin) 131 | } 132 | } 133 | 134 | impl Gpio { 135 | #[inline] 136 | pub fn into_floating_input(mut self) -> Gpio> { 137 | self.pin.set_io_pull(Pull::None); 138 | self.direction_in(); 139 | Gpio { 140 | gpio: self.gpio, 141 | pin: self.pin, 142 | _mode: PhantomData, 143 | } 144 | } 145 | 146 | #[inline] 147 | pub fn into_pull_up_input(mut self) -> Gpio> { 148 | self.pin.set_io_pull(Pull::Up); 149 | self.direction_in(); 150 | Gpio { 151 | gpio: self.gpio, 152 | pin: self.pin, 153 | _mode: PhantomData, 154 | } 155 | } 156 | 157 | #[inline] 158 | pub fn into_pull_down_input(mut self) -> Gpio> { 159 | self.pin.set_io_pull(Pull::Down); 160 | self.direction_in(); 161 | Gpio { 162 | gpio: self.gpio, 163 | pin: self.pin, 164 | _mode: PhantomData, 165 | } 166 | } 167 | 168 | #[inline] 169 | pub fn into_push_pull_output(mut self) -> Gpio { 170 | self.pin.set_io_pull(Pull::Down); 171 | self.direction_out(); 172 | Gpio { 173 | gpio: self.gpio, 174 | pin: self.pin, 175 | _mode: PhantomData, 176 | } 177 | } 178 | 179 | #[inline] 180 | fn direction_in(&mut self) { 181 | unsafe { 182 | let p = &(*pac::GPIO::ptr()).direction as *const _ as *mut _; 183 | u32_set_bit(p, false, GPIO::INDEX as usize); 184 | } 185 | } 186 | 187 | #[inline] 188 | fn direction_out(&mut self) { 189 | unsafe { 190 | let p = &(*pac::GPIO::ptr()).direction as *const _ as *mut _; 191 | u32_set_bit(p, true, GPIO::INDEX as usize); 192 | } 193 | } 194 | } 195 | 196 | impl ErrorType for Gpio { 197 | // All GPIO operations are infallible. 198 | type Error = core::convert::Infallible; 199 | } 200 | 201 | impl InputPin for Gpio> { 202 | #[inline] 203 | fn is_high(&mut self) -> Result { 204 | Ok(unsafe { 205 | let p = &(*pac::GPIO::ptr()).data_input as *const _ as *const _; 206 | u32_bit_is_set(p, GPIO::INDEX as usize) 207 | }) 208 | } 209 | 210 | #[inline] 211 | fn is_low(&mut self) -> Result { 212 | Ok(unsafe { 213 | let p = &(*pac::GPIO::ptr()).data_input as *const _ as *const _; 214 | u32_bit_is_clear(p, GPIO::INDEX as usize) 215 | }) 216 | } 217 | } 218 | 219 | impl OutputPin for Gpio { 220 | #[inline] 221 | fn set_high(&mut self) -> Result<(), Self::Error> { 222 | unsafe { 223 | let p = &(*pac::GPIO::ptr()).data_output as *const _ as *mut _; 224 | u32_set_bit(p, true, GPIO::INDEX as usize); 225 | } 226 | Ok(()) 227 | } 228 | 229 | #[inline] 230 | fn set_low(&mut self) -> Result<(), Self::Error> { 231 | unsafe { 232 | let p = &(*pac::GPIO::ptr()).data_output as *const _ as *mut _; 233 | u32_set_bit(p, false, GPIO::INDEX as usize); 234 | } 235 | Ok(()) 236 | } 237 | } 238 | 239 | impl StatefulOutputPin for Gpio { 240 | #[inline] 241 | fn is_set_high(&mut self) -> Result { 242 | Ok(unsafe { 243 | let p = &(*pac::GPIO::ptr()).data_output as *const _ as *const _; 244 | u32_bit_is_set(p, GPIO::INDEX as usize) 245 | }) 246 | } 247 | 248 | #[inline] 249 | fn is_set_low(&mut self) -> Result { 250 | Ok(unsafe { 251 | let p = &(*pac::GPIO::ptr()).data_output as *const _ as *const _; 252 | u32_bit_is_clear(p, GPIO::INDEX as usize) 253 | }) 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/gpiohs.rs: -------------------------------------------------------------------------------- 1 | //! High-speed GPIO peripheral (GPIOHS) 2 | 3 | use crate::bit_utils::{u32_bit_is_clear, u32_bit_is_set, u32_set_bit}; 4 | use crate::pac::GPIOHS; 5 | use core::marker::PhantomData; 6 | use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; 7 | 8 | // todo: verify 9 | 10 | /// Floating mode (type state) 11 | pub struct Floating; 12 | 13 | /// PullUp mode (type state) 14 | pub struct PullUp; 15 | 16 | /// Input mode (type state) 17 | pub struct Input(MODE); 18 | 19 | /// Output mode (type state) 20 | pub struct Output(MODE); 21 | 22 | pub trait GpiohsExt { 23 | fn split(self) -> Parts; 24 | } 25 | 26 | impl GpiohsExt for GPIOHS { 27 | fn split(self) -> Parts { 28 | Parts { 29 | gpiohs0: Gpiohs0 { _mode: PhantomData }, 30 | } 31 | } 32 | } 33 | 34 | pub struct Parts { 35 | pub gpiohs0: Gpiohs0>, 36 | } 37 | 38 | pub struct Gpiohs0 { 39 | _mode: PhantomData, 40 | } 41 | 42 | impl Gpiohs0 { 43 | #[inline] 44 | pub fn into_pull_up_input(self) -> Gpiohs0> { 45 | GPIOHS::set_output_en(0, false); 46 | GPIOHS::set_input_en(0, true); 47 | GPIOHS::set_pullup_en(0, true); 48 | Gpiohs0 { _mode: PhantomData } 49 | } 50 | 51 | // todo: all modes 52 | } 53 | 54 | bitflags::bitflags! { 55 | pub struct Edge: u8 { 56 | const RISING = 0b00000001; 57 | const FALLING = 0b00000010; 58 | const HIGH = 0b00000100; 59 | const LOW = 0b00001000; 60 | } 61 | } 62 | 63 | impl Gpiohs0 { 64 | #[inline] 65 | pub fn trigger_on_edge(&mut self, edge: Edge) { 66 | // clear all pending bits 67 | GPIOHS::clear_rise_ip(0); 68 | GPIOHS::clear_fall_ip(0); 69 | GPIOHS::clear_high_ip(0); 70 | GPIOHS::clear_low_ip(0); 71 | // enable interrupts according to flags 72 | GPIOHS::set_rise_ie(0, edge.contains(Edge::RISING)); 73 | GPIOHS::set_fall_ie(0, edge.contains(Edge::FALLING)); 74 | GPIOHS::set_high_ie(0, edge.contains(Edge::HIGH)); 75 | GPIOHS::set_low_ie(0, edge.contains(Edge::LOW)); 76 | } 77 | 78 | #[inline] 79 | pub fn check_edges(&self) -> Edge { 80 | let mut ans = Edge::empty(); 81 | if GPIOHS::has_rise_ip(0) { 82 | ans |= Edge::RISING; 83 | } 84 | if GPIOHS::has_fall_ip(0) { 85 | ans |= Edge::FALLING; 86 | } 87 | if GPIOHS::has_high_ip(0) { 88 | ans |= Edge::HIGH; 89 | } 90 | if GPIOHS::has_low_ip(0) { 91 | ans |= Edge::LOW; 92 | } 93 | ans 94 | } 95 | 96 | #[inline] 97 | pub fn clear_interrupt_pending_bits(&mut self) { 98 | if GPIOHS::has_rise_ie(0) { 99 | GPIOHS::set_rise_ie(0, false); 100 | GPIOHS::clear_rise_ip(0); 101 | GPIOHS::set_rise_ie(0, true); 102 | } 103 | if GPIOHS::has_fall_ie(0) { 104 | GPIOHS::set_fall_ie(0, false); 105 | GPIOHS::clear_fall_ip(0); 106 | GPIOHS::set_fall_ie(0, true); 107 | } 108 | if GPIOHS::has_high_ie(0) { 109 | GPIOHS::set_high_ie(0, false); 110 | GPIOHS::clear_high_ip(0); 111 | GPIOHS::set_high_ie(0, true); 112 | } 113 | if GPIOHS::has_low_ie(0) { 114 | GPIOHS::set_low_ie(0, false); 115 | GPIOHS::clear_low_ip(0); 116 | GPIOHS::set_low_ie(0, true); 117 | } 118 | } 119 | } 120 | 121 | impl ErrorType for Gpiohs0 { 122 | // All GPIO operations are infallible. 123 | type Error = core::convert::Infallible; 124 | } 125 | 126 | impl InputPin for Gpiohs0> { 127 | #[inline] 128 | fn is_high(&mut self) -> Result { 129 | Ok(unsafe { 130 | let p = &(*GPIOHS::ptr()).input_val as *const _ as *const _; 131 | u32_bit_is_set(p, 0) 132 | }) 133 | } 134 | 135 | #[inline] 136 | fn is_low(&mut self) -> Result { 137 | Ok(unsafe { 138 | let p = &(*GPIOHS::ptr()).input_val as *const _ as *const _; 139 | u32_bit_is_clear(p, 0) 140 | }) 141 | } 142 | } 143 | 144 | impl OutputPin for Gpiohs0> { 145 | #[inline] 146 | fn set_high(&mut self) -> Result<(), Self::Error> { 147 | unsafe { 148 | let p = &(*GPIOHS::ptr()).output_val as *const _ as *mut _; 149 | u32_set_bit(p, true, 0); 150 | } 151 | Ok(()) 152 | } 153 | 154 | #[inline] 155 | fn set_low(&mut self) -> Result<(), Self::Error> { 156 | unsafe { 157 | let p = &(*GPIOHS::ptr()).output_val as *const _ as *mut _; 158 | u32_set_bit(p, false, 0); 159 | } 160 | Ok(()) 161 | } 162 | } 163 | 164 | trait GpiohsAccess { 165 | fn peripheral() -> &'static mut crate::pac::gpiohs::RegisterBlock; 166 | 167 | #[inline] 168 | fn set_drive(index: usize, bit: bool) { 169 | unsafe { 170 | let p = &mut Self::peripheral().drive as *mut _ as *mut _; 171 | u32_set_bit(p, bit, index); 172 | } 173 | } 174 | 175 | #[inline] 176 | fn input_value(index: usize) -> bool { 177 | unsafe { 178 | let p = &mut Self::peripheral().input_val as *mut _ as *mut _; 179 | u32_bit_is_set(p, index) 180 | } 181 | } 182 | 183 | #[inline] 184 | fn set_input_en(index: usize, bit: bool) { 185 | unsafe { 186 | let p = &mut Self::peripheral().input_en as *mut _ as *mut _; 187 | u32_set_bit(p, bit, index); 188 | } 189 | } 190 | 191 | #[inline] 192 | fn set_iof_en(index: usize, bit: bool) { 193 | unsafe { 194 | let p = &mut Self::peripheral().iof_en as *mut _ as *mut _; 195 | u32_set_bit(p, bit, index); 196 | } 197 | } 198 | 199 | #[inline] 200 | fn set_iof_sel(index: usize, bit: bool) { 201 | unsafe { 202 | let p = &mut Self::peripheral().iof_sel as *mut _ as *mut _; 203 | u32_set_bit(p, bit, index); 204 | } 205 | } 206 | 207 | #[inline] 208 | fn set_output_en(index: usize, bit: bool) { 209 | unsafe { 210 | let p = &mut Self::peripheral().output_en as *mut _ as *mut _; 211 | u32_set_bit(p, bit, index); 212 | } 213 | } 214 | 215 | #[inline] 216 | fn set_output_value(index: usize, bit: bool) { 217 | unsafe { 218 | let p = &mut Self::peripheral().output_val as *mut _ as *mut _; 219 | u32_set_bit(p, bit, index); 220 | } 221 | } 222 | 223 | #[inline] 224 | fn set_output_xor(index: usize, bit: bool) { 225 | unsafe { 226 | let p = &mut Self::peripheral().output_xor as *mut _ as *mut _; 227 | u32_set_bit(p, bit, index); 228 | } 229 | } 230 | 231 | #[inline] 232 | fn set_pullup_en(index: usize, bit: bool) { 233 | unsafe { 234 | let p = &mut Self::peripheral().pullup_en as *mut _ as *mut _; 235 | u32_set_bit(p, bit, index); 236 | } 237 | } 238 | 239 | #[inline] 240 | fn set_rise_ie(index: usize, bit: bool) { 241 | unsafe { 242 | let p = &mut Self::peripheral().rise_ie as *mut _ as *mut _; 243 | u32_set_bit(p, bit, index); 244 | } 245 | } 246 | 247 | #[inline] 248 | fn clear_rise_ip(index: usize) { 249 | unsafe { 250 | let p = &mut Self::peripheral().rise_ip as *mut _ as *mut _; 251 | u32_set_bit(p, true, index); 252 | } 253 | } 254 | 255 | #[inline] 256 | fn set_fall_ie(index: usize, bit: bool) { 257 | unsafe { 258 | let p = &mut Self::peripheral().fall_ie as *mut _ as *mut _; 259 | u32_set_bit(p, bit, index); 260 | } 261 | } 262 | 263 | #[inline] 264 | fn clear_fall_ip(index: usize) { 265 | unsafe { 266 | let p = &mut Self::peripheral().fall_ip as *mut _ as *mut _; 267 | u32_set_bit(p, true, index); 268 | } 269 | } 270 | 271 | #[inline] 272 | fn set_high_ie(index: usize, bit: bool) { 273 | unsafe { 274 | let p = &mut Self::peripheral().high_ie as *mut _ as *mut _; 275 | u32_set_bit(p, bit, index); 276 | } 277 | } 278 | 279 | #[inline] 280 | fn clear_high_ip(index: usize) { 281 | unsafe { 282 | let p = &mut Self::peripheral().high_ip as *mut _ as *mut _; 283 | u32_set_bit(p, true, index); 284 | } 285 | } 286 | 287 | #[inline] 288 | fn set_low_ie(index: usize, bit: bool) { 289 | unsafe { 290 | let p = &mut Self::peripheral().low_ie as *mut _ as *mut _; 291 | u32_set_bit(p, bit, index); 292 | } 293 | } 294 | 295 | #[inline] 296 | fn clear_low_ip(index: usize) { 297 | unsafe { 298 | let p = &mut Self::peripheral().low_ip as *mut _ as *mut _; 299 | u32_set_bit(p, true, index); 300 | } 301 | } 302 | 303 | #[inline] 304 | fn has_rise_ie(index: usize) -> bool { 305 | unsafe { 306 | let p = &mut Self::peripheral().rise_ie as *mut _ as *mut _; 307 | u32_bit_is_set(p, index) 308 | } 309 | } 310 | 311 | #[inline] 312 | fn has_fall_ie(index: usize) -> bool { 313 | unsafe { 314 | let p = &mut Self::peripheral().fall_ie as *mut _ as *mut _; 315 | u32_bit_is_set(p, index) 316 | } 317 | } 318 | 319 | #[inline] 320 | fn has_high_ie(index: usize) -> bool { 321 | unsafe { 322 | let p = &mut Self::peripheral().high_ie as *mut _ as *mut _; 323 | u32_bit_is_set(p, index) 324 | } 325 | } 326 | 327 | #[inline] 328 | fn has_low_ie(index: usize) -> bool { 329 | unsafe { 330 | let p = &mut Self::peripheral().low_ie as *mut _ as *mut _; 331 | u32_bit_is_set(p, index) 332 | } 333 | } 334 | 335 | #[inline] 336 | fn has_rise_ip(index: usize) -> bool { 337 | unsafe { 338 | let p = &mut Self::peripheral().rise_ip as *mut _ as *mut _; 339 | u32_bit_is_set(p, index) 340 | } 341 | } 342 | 343 | #[inline] 344 | fn has_fall_ip(index: usize) -> bool { 345 | unsafe { 346 | let p = &mut Self::peripheral().fall_ip as *mut _ as *mut _; 347 | u32_bit_is_set(p, index) 348 | } 349 | } 350 | 351 | #[inline] 352 | fn has_high_ip(index: usize) -> bool { 353 | unsafe { 354 | let p = &mut Self::peripheral().high_ip as *mut _ as *mut _; 355 | u32_bit_is_set(p, index) 356 | } 357 | } 358 | 359 | #[inline] 360 | fn has_low_ip(index: usize) -> bool { 361 | unsafe { 362 | let p = &mut Self::peripheral().low_ip as *mut _ as *mut _; 363 | u32_bit_is_set(p, index) 364 | } 365 | } 366 | } 367 | 368 | impl GpiohsAccess for GPIOHS { 369 | #[inline] 370 | fn peripheral() -> &'static mut crate::pac::gpiohs::RegisterBlock { 371 | unsafe { &mut *(GPIOHS::ptr() as *mut _) } 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! HAL for the K210 SoC 2 | //! 3 | //! This is an implementation of the [`embedded-hal`] traits for the K210 SoC 4 | 5 | // #![deny(missing_docs)] // uncomment for every releases 6 | #![no_std] 7 | 8 | pub use k210_pac as pac; 9 | 10 | pub mod aes; 11 | pub mod apu; 12 | pub mod cache; 13 | pub mod clint; 14 | pub mod clock; 15 | pub mod dmac; 16 | pub mod fft; 17 | pub mod fpioa; 18 | pub mod gpio; 19 | pub mod gpiohs; 20 | pub mod plic; 21 | pub mod serial; 22 | pub mod sha256; 23 | pub mod spi; 24 | pub mod sysctl; 25 | pub mod time; 26 | 27 | /// Prelude 28 | pub mod prelude { 29 | pub use crate::fpioa::FpioaExt as _k210_hal_fpioa_FpioaExt; 30 | pub use crate::gpio::GpioExt as _k210_hal_gpio_GpioExt; 31 | pub use crate::gpiohs::GpiohsExt as _k210_hal_gpiohs_GpiohsExt; 32 | pub use crate::plic::PlicExt as _k210_hal_plic_PlicExt; 33 | pub use crate::serial::SerialExt as _k210_hal_serial_SerialExt; 34 | pub use crate::sysctl::SysctlExt as _k210_hal_sysctl_SysctlExt; 35 | pub use crate::time::U32Ext as _k210_hal_time_U32Ext; 36 | } 37 | 38 | mod bit_utils { 39 | #[inline(always)] 40 | pub(crate) unsafe fn u32_set_bit(p: *mut u32, bit: bool, index: usize) { 41 | let mask = 1 << index; 42 | if bit { 43 | *p |= mask; 44 | } else { 45 | *p &= !mask; 46 | } 47 | } 48 | 49 | #[inline(always)] 50 | pub(crate) unsafe fn u32_bit_is_set(r: *const u32, index: usize) -> bool { 51 | (*r & 1 << index) != 0 52 | } 53 | 54 | #[inline(always)] 55 | pub(crate) unsafe fn u32_bit_is_clear(r: *const u32, index: usize) -> bool { 56 | (*r & 1 << index) == 0 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/plic.rs: -------------------------------------------------------------------------------- 1 | //! Platform-Level Interrupt Controller (PLIC) 2 | 3 | // I don't know if this part should be implemented in runtime 4 | // keep by now, may be replaced on further designs 5 | // #[doc(hidden)] 6 | // #[link_name = "MachineExternal"] 7 | // pub extern fn machine_external() { 8 | 9 | // } 10 | 11 | use crate::pac::{Interrupt, PLIC}; 12 | 13 | /// Extension trait for PLIC interrupt controller peripheral 14 | pub trait PlicExt { 15 | /// Interrupt wrapper type 16 | type Interrupt: Nr; 17 | /// Is this M-Mode interrupt enabled on given hart? 18 | fn is_enabled(hart_id: usize, interrupt: Self::Interrupt) -> bool; 19 | /// Enable an interrupt for a given hart 20 | /// 21 | /// # Safety 22 | /// 23 | /// May effect normal interrupt handling procedure 24 | unsafe fn unmask(hart_id: usize, interrupt: Self::Interrupt); 25 | /// Disable an interrupt for a given hart 26 | fn mask(hart_id: usize, interrupt: Self::Interrupt); 27 | /// Get global priority for one interrupt 28 | fn get_priority(interrupt: Self::Interrupt) -> Priority; 29 | /// Globally set priority for one interrupt 30 | /// 31 | /// # Safety 32 | /// 33 | /// May effect normal interrupt handling procedure 34 | unsafe fn set_priority(interrupt: Self::Interrupt, prio: Priority); 35 | /// Get priority threshold for a given hart 36 | fn get_threshold(hart_id: usize) -> Priority; 37 | /// Set the priority threshold for a given hart 38 | /// 39 | /// # Safety 40 | /// 41 | /// May effect normal interrupt handling procedure 42 | unsafe fn set_threshold(hart_id: usize, threshold: Priority); 43 | /// Mark that given hart have claimed to handle this interrupt 44 | fn claim(hart_id: usize) -> Option; 45 | /// Mark that given hart have completed handling this interrupt 46 | fn complete(hart_id: usize, interrupt: Self::Interrupt); 47 | /// Is this interrupt claimed and under procceeding? 48 | fn is_pending(interrupt: Self::Interrupt) -> bool; 49 | } 50 | 51 | impl PlicExt for PLIC { 52 | type Interrupt = Interrupt; 53 | fn is_enabled(hart_id: usize, interrupt: Interrupt) -> bool { 54 | let irq_number = interrupt.into_bits() as usize; 55 | unsafe { 56 | (*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32] 57 | .read() 58 | .bits() 59 | & 1 << (irq_number % 32) 60 | != 0 61 | } 62 | } 63 | unsafe fn unmask(hart_id: usize, interrupt: Interrupt) { 64 | let irq_number = interrupt.into_bits() as usize; 65 | (*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32] 66 | .modify(|r, w| w.bits(r.bits() | 1 << (irq_number % 32))); 67 | } 68 | fn mask(hart_id: usize, interrupt: Interrupt) { 69 | let irq_number = interrupt.into_bits() as usize; 70 | unsafe { 71 | (*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32] 72 | .modify(|r, w| w.bits(r.bits() & !(1 << (irq_number % 32)))); 73 | } 74 | } 75 | fn get_priority(interrupt: Interrupt) -> Priority { 76 | let irq_number = interrupt.into_bits() as usize; 77 | let bits = unsafe { (*PLIC::ptr()).priority[irq_number].read().bits() }; 78 | Priority::from_bits(bits) 79 | } 80 | unsafe fn set_priority(interrupt: Interrupt, prio: Priority) { 81 | let irq_number = interrupt.into_bits() as usize; 82 | (*PLIC::ptr()).priority[irq_number].write(|w| w.bits(prio.into_bits())); 83 | } 84 | fn get_threshold(hart_id: usize) -> Priority { 85 | let bits = unsafe { (*PLIC::ptr()).targets[hart_id].threshold.read().bits() }; 86 | Priority::from_bits(bits) 87 | } 88 | unsafe fn set_threshold(hart_id: usize, threshold: Priority) { 89 | (*PLIC::ptr()).targets[hart_id] 90 | .threshold 91 | .write(|w| w.bits(threshold.into_bits())); 92 | } 93 | fn claim(hart_id: usize) -> Option { 94 | let bits = unsafe { (*PLIC::ptr()).targets[hart_id].claim.read().bits() }; 95 | Nr::from_bits(bits) 96 | } 97 | fn complete(hart_id: usize, interrupt: Interrupt) { 98 | unsafe { 99 | (*PLIC::ptr()).targets[hart_id] 100 | .claim 101 | .write(|w| w.bits(interrupt.into_bits())); 102 | } 103 | } 104 | fn is_pending(interrupt: Interrupt) -> bool { 105 | let irq_number = interrupt.into_bits() as usize; 106 | unsafe { 107 | (*PLIC::ptr()).pending[irq_number / 32].read().bits() & 1 << (irq_number % 32) != 0 108 | } 109 | } 110 | } 111 | 112 | impl Nr for Interrupt { 113 | fn into_bits(self) -> u32 { 114 | self as u8 as u32 115 | } 116 | fn from_bits(bits: u32) -> Option { 117 | use Interrupt::*; 118 | match bits { 119 | 0 => None, 120 | 1 => Some(SPI0), 121 | 2 => Some(SPI1), 122 | 3 => Some(SPI_SLAVE), 123 | 4 => Some(SPI3), 124 | 5 => Some(I2S0), 125 | 6 => Some(I2S1), 126 | 7 => Some(I2S2), 127 | 8 => Some(I2C0), 128 | 9 => Some(I2C1), 129 | 10 => Some(I2C2), 130 | 11 => Some(UART1), 131 | 12 => Some(UART2), 132 | 13 => Some(UART3), 133 | 14 => Some(TIMER0A), 134 | 15 => Some(TIMER0B), 135 | 16 => Some(TIMER1A), 136 | 17 => Some(TIMER1B), 137 | 18 => Some(TIMER2A), 138 | 19 => Some(TIMER2B), 139 | 20 => Some(RTC), 140 | 21 => Some(WDT0), 141 | 22 => Some(WDT1), 142 | 23 => Some(APB_GPIO), 143 | 24 => Some(DVP), 144 | 25 => Some(KPU), 145 | 26 => Some(FFT), 146 | 27 => Some(DMA0), 147 | 28 => Some(DMA1), 148 | 29 => Some(DMA2), 149 | 30 => Some(DMA3), 150 | 31 => Some(DMA4), 151 | 32 => Some(DMA5), 152 | 33 => Some(UARTHS), 153 | 34 => Some(GPIOHS0), 154 | 35 => Some(GPIOHS1), 155 | 36 => Some(GPIOHS2), 156 | 37 => Some(GPIOHS3), 157 | 38 => Some(GPIOHS4), 158 | 39 => Some(GPIOHS5), 159 | 40 => Some(GPIOHS6), 160 | 41 => Some(GPIOHS7), 161 | 42 => Some(GPIOHS8), 162 | 43 => Some(GPIOHS9), 163 | 44 => Some(GPIOHS10), 164 | 45 => Some(GPIOHS11), 165 | 46 => Some(GPIOHS12), 166 | 47 => Some(GPIOHS13), 167 | 48 => Some(GPIOHS14), 168 | 49 => Some(GPIOHS15), 169 | 50 => Some(GPIOHS16), 170 | 51 => Some(GPIOHS17), 171 | 52 => Some(GPIOHS18), 172 | 53 => Some(GPIOHS19), 173 | 54 => Some(GPIOHS20), 174 | 55 => Some(GPIOHS21), 175 | 56 => Some(GPIOHS22), 176 | 57 => Some(GPIOHS23), 177 | 58 => Some(GPIOHS24), 178 | 59 => Some(GPIOHS25), 179 | 60 => Some(GPIOHS26), 180 | 61 => Some(GPIOHS27), 181 | 62 => Some(GPIOHS28), 182 | 63 => Some(GPIOHS29), 183 | 64 => Some(GPIOHS30), 184 | 65 => Some(GPIOHS31), 185 | _ => panic!("invalid interrupt bits"), 186 | } 187 | } 188 | } 189 | 190 | #[doc(hidden)] 191 | pub trait Nr: Sized + Copy { 192 | fn into_bits(self) -> u32; 193 | fn from_bits(bits: u32) -> Option; 194 | } 195 | 196 | /// Priority of an interrupt 197 | #[derive(Clone, Copy, Debug)] 198 | pub enum Priority { 199 | /// Priority 0: Never interrupt 200 | P0, 201 | /// Priority 1: Lowest active priority 202 | P1, 203 | /// Priority 2 204 | P2, 205 | /// Priority 3 206 | P3, 207 | /// Priority 4 208 | P4, 209 | /// Priority 5 210 | P5, 211 | /// Priority 6 212 | P6, 213 | /// Priority 7: Highest priority 214 | P7, 215 | } 216 | 217 | impl Priority { 218 | fn into_bits(self) -> u32 { 219 | match self { 220 | Priority::P0 => 0, 221 | Priority::P1 => 1, 222 | Priority::P2 => 2, 223 | Priority::P3 => 3, 224 | Priority::P4 => 4, 225 | Priority::P5 => 5, 226 | Priority::P6 => 6, 227 | Priority::P7 => 7, 228 | } 229 | } 230 | fn from_bits(prio: u32) -> Priority { 231 | match prio { 232 | 0 => Priority::P0, 233 | 1 => Priority::P1, 234 | 2 => Priority::P2, 235 | 3 => Priority::P3, 236 | 4 => Priority::P4, 237 | 5 => Priority::P5, 238 | 6 => Priority::P6, 239 | 7 => Priority::P7, 240 | _ => panic!("Invalid priority"), 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/serial.rs: -------------------------------------------------------------------------------- 1 | //! Serial interface 2 | //! 3 | //! You can use the `Serial` interface with these UART instances: 4 | //! * [`UARTHS`](crate::pac::UARTHS) 5 | //! * [`UART1`](crate::pac::UART1) 6 | //! * [`UART2`](crate::pac::UART2) 7 | //! * [`UART3`](crate::pac::UART3) 8 | 9 | use core::convert::Infallible; 10 | use core::mem; 11 | 12 | use crate::clock::Clocks; 13 | use crate::pac::{uart1, UART1, UART2, UART3, UARTHS}; 14 | use crate::time::Bps; 15 | 16 | /// Extension trait that constrains UART peripherals 17 | pub trait SerialExt: Sized { 18 | /// Configures a UART peripheral to provide serial communication 19 | fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial; 20 | } 21 | 22 | /// Serial abstraction 23 | pub struct Serial { 24 | uart: UART, 25 | } 26 | 27 | impl Serial { 28 | /// Splits the `Serial` abstraction into a transmitter and a 29 | /// receiver half 30 | #[inline] 31 | pub fn split(self) -> (Tx, Rx) { 32 | ( 33 | Tx { uart: self.uart }, 34 | Rx { 35 | // clippy allow: inner marker variable only indicates ownership, does not include actual data 36 | uart: unsafe { 37 | #[allow(clippy::uninit_assumed_init)] 38 | mem::MaybeUninit::uninit().assume_init() 39 | }, 40 | }, 41 | ) 42 | } 43 | 44 | /// Forms `Serial` abstraction from a transmitter and a 45 | /// receiver half 46 | #[inline] 47 | pub fn join(tx: Tx, rx: Rx) -> Self { 48 | let _ = rx; // note(discard): Zero-sized typestate struct 49 | Serial { uart: tx.uart } 50 | } 51 | 52 | /// Releases the UART peripheral 53 | #[inline] 54 | pub fn free(self) -> UART { 55 | // todo: power down this UART 56 | self.uart 57 | } 58 | } 59 | 60 | /// Serial transmitter 61 | pub struct Tx { 62 | uart: UART, 63 | } 64 | 65 | /// Serial receiver 66 | pub struct Rx { 67 | uart: UART, 68 | } 69 | 70 | impl SerialExt for UARTHS { 71 | #[inline] 72 | fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial { 73 | let uart = self; 74 | 75 | let div = clocks.cpu().0 / baud_rate.0 - 1; 76 | unsafe { 77 | uart.div.write(|w| w.bits(div)); 78 | } 79 | 80 | uart.txctrl.write(|w| w.txen().bit(true)); 81 | uart.rxctrl.write(|w| w.rxen().bit(true)); 82 | 83 | Serial { uart } 84 | } 85 | } 86 | 87 | impl Serial { 88 | /// Starts listening for an interrupt event 89 | #[inline] 90 | pub fn listen(self) -> Self { 91 | self.uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(true)); 92 | self 93 | } 94 | 95 | /// Stops listening for an interrupt event 96 | #[inline] 97 | pub fn unlisten(self) -> Self { 98 | self.uart 99 | .ie 100 | .write(|w| w.txwm().bit(false).rxwm().bit(false)); 101 | self 102 | } 103 | } 104 | 105 | impl embedded_io::ErrorType for Rx { 106 | type Error = core::convert::Infallible; 107 | } 108 | 109 | impl embedded_io::Read for Rx { 110 | #[inline] 111 | fn read(&mut self, buf: &mut [u8]) -> Result { 112 | while self.uart.rxdata.read().empty().bit_is_set() { 113 | // Block until rxdata available. 114 | core::hint::spin_loop() 115 | } 116 | let len = buf.len(); 117 | for slot in buf { 118 | *slot = self.uart.rxdata.read().data().bits(); 119 | } 120 | Ok(len) 121 | } 122 | } 123 | 124 | impl embedded_io::ErrorType for Tx { 125 | type Error = core::convert::Infallible; 126 | } 127 | 128 | impl embedded_io::Write for Tx { 129 | #[inline] 130 | fn write(&mut self, bytes: &[u8]) -> Result { 131 | while self.uart.txdata.read().full().bit_is_set() { 132 | // Block until txdata available. 133 | core::hint::spin_loop() 134 | } 135 | for byte in bytes { 136 | unsafe { 137 | self.uart.txdata.write(|w| w.data().bits(*byte)); 138 | } 139 | } 140 | Ok(bytes.len()) 141 | } 142 | 143 | #[inline] 144 | fn flush(&mut self) -> Result<(), Infallible> { 145 | while self.uart.txdata.read().full().bit_is_set() { 146 | // Block until flush complete. If you don't want a block, use embedded_io_async traits instead. 147 | core::hint::spin_loop() 148 | } 149 | Ok(()) 150 | } 151 | } 152 | 153 | mod closed_trait { 154 | use core::ops::Deref; 155 | /// Trait to be able to generalize over UART1/UART2/UART3 156 | pub trait UartX: Deref { 157 | const INDEX: u8; 158 | } 159 | } 160 | use closed_trait::UartX; 161 | 162 | impl UartX for UART1 { 163 | const INDEX: u8 = 1; 164 | } 165 | impl UartX for UART2 { 166 | const INDEX: u8 = 2; 167 | } 168 | impl UartX for UART3 { 169 | const INDEX: u8 = 3; 170 | } 171 | 172 | const UART_RECEIVE_FIFO_1: u32 = 0; 173 | const UART_SEND_FIFO_8: u32 = 3; 174 | 175 | impl SerialExt for UART { 176 | #[inline] 177 | fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial { 178 | let uart = self; 179 | 180 | // Hardcode these for now: 181 | let data_width = 8; // 8 data bits 182 | let stopbit_val = 0; // 1 stop bit 183 | let parity_val = 0; // No parity 184 | // Note: need to make sure that UARTx clock is enabled through sysctl before here 185 | let divisor = clocks.apb0().0 / baud_rate.0; 186 | let dlh = ((divisor >> 12) & 0xff) as u8; 187 | let dll = ((divisor >> 4) & 0xff) as u8; 188 | let dlf = (divisor & 0xf) as u8; 189 | unsafe { 190 | // Set Divisor Latch Access Bit (enables DLL DLH) to set baudrate 191 | uart.lcr.write(|w| w.bits(1 << 7)); 192 | uart.dlh_ier.write(|w| w.bits(dlh.into())); 193 | uart.rbr_dll_thr.write(|w| w.bits(dll.into())); 194 | uart.dlf.write(|w| w.bits(dlf.into())); 195 | // Clear Divisor Latch Access Bit after setting baudrate 196 | uart.lcr 197 | .write(|w| w.bits((data_width - 5) | (stopbit_val << 2) | (parity_val << 3))); 198 | // Write IER 199 | uart.dlh_ier.write(|w| w.bits(0x80)); /* THRE */ 200 | // Write FCT 201 | uart.fcr_iir.write(|w| { 202 | w.bits(UART_RECEIVE_FIFO_1 << 6 | UART_SEND_FIFO_8 << 4 | 0x1 << 3 | 0x1) 203 | }); 204 | } 205 | 206 | Serial { uart } 207 | } 208 | } 209 | 210 | impl Serial { 211 | /// Starts listening for an interrupt event 212 | #[inline] 213 | pub fn listen(self) -> Self { 214 | // TODO 215 | self 216 | } 217 | 218 | /// Stops listening for an interrupt event 219 | #[inline] 220 | pub fn unlisten(self) -> Self { 221 | // TODO 222 | self 223 | } 224 | } 225 | 226 | impl embedded_io::ErrorType for Rx { 227 | type Error = core::convert::Infallible; 228 | } 229 | 230 | impl embedded_io::Read for Rx { 231 | #[inline] 232 | fn read(&mut self, buf: &mut [u8]) -> Result { 233 | while (self.uart.lsr.read().bits() & (1 << 0)) == 0 { 234 | // Data Ready bit 235 | core::hint::spin_loop() 236 | } 237 | let len = buf.len(); 238 | for slot in buf { 239 | *slot = (self.uart.rbr_dll_thr.read().bits() & 0xff) as u8; 240 | } 241 | Ok(len) 242 | } 243 | } 244 | 245 | impl embedded_io::ErrorType for Tx { 246 | type Error = core::convert::Infallible; 247 | } 248 | 249 | impl embedded_io::Write for Tx { 250 | #[inline] 251 | fn write(&mut self, bytes: &[u8]) -> Result { 252 | while (self.uart.lsr.read().bits() & (1 << 5)) != 0 { 253 | // Transmit Holding Register Empty bit 254 | core::hint::spin_loop(); 255 | } 256 | for byte in bytes { 257 | unsafe { 258 | self.uart.rbr_dll_thr.write(|w| w.bits(*byte as u32)); 259 | } 260 | } 261 | Ok(bytes.len()) 262 | } 263 | 264 | #[inline] 265 | fn flush(&mut self) -> Result<(), Infallible> { 266 | // TODO 267 | Ok(()) 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /src/sha256.rs: -------------------------------------------------------------------------------- 1 | //! Secure Hash Algorithm-256 (SHA256) 2 | 3 | use crate::pac::SHA256; 4 | use crate::sysctl::{self, APB0}; 5 | 6 | /// SHA256 module abstraction 7 | pub struct Sha256 { 8 | sha256: SHA256, 9 | } 10 | 11 | impl Sha256 { 12 | pub fn new(sha256: SHA256, apb0: &mut APB0) -> Sha256 { 13 | apb0.enable(); 14 | sysctl::clk_en_peri().modify(|_r, w| w.sha_clk_en().set_bit()); 15 | sysctl::peri_reset().modify(|_r, w| w.sha_reset().set_bit()); 16 | sysctl::peri_reset().modify(|_r, w| w.sha_reset().clear_bit()); 17 | Sha256 { sha256 } 18 | } 19 | 20 | pub fn new_digest(self) -> Digest { 21 | todo!() 22 | } 23 | 24 | pub fn release(self) -> SHA256 { 25 | sysctl::clk_en_peri().modify(|_r, w| w.sha_clk_en().clear_bit()); 26 | self.sha256 27 | } 28 | } 29 | 30 | pub struct Digest { 31 | sha256: SHA256, 32 | } 33 | 34 | impl Digest { 35 | pub fn write_u32(&mut self, n: u32) { 36 | let _todo = n; 37 | todo!() 38 | } 39 | 40 | pub fn finish(&self, out: &mut [u8; 32]) { 41 | let _todo = out; 42 | todo!() 43 | } 44 | 45 | pub fn free(self) -> Sha256 { 46 | Sha256 { 47 | sha256: self.sha256, 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/spi.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) Serial Peripheral Interface (SPI) 2 | 3 | use crate::clock::Clocks; 4 | use crate::pac::SPI0; 5 | use crate::sysctl::{self, APB0}; 6 | pub use embedded_hal::spi::{Mode, Phase, Polarity}; 7 | 8 | /// 9 | pub struct Spi { 10 | spi: SPI, 11 | } 12 | 13 | impl Spi { 14 | #[inline] 15 | pub fn spi0( 16 | spi: SPI0, 17 | mode: Mode, 18 | frame_format: FrameFormat, 19 | endian: Endian, 20 | clock: &Clocks, 21 | apb0: &mut APB0, 22 | ) -> Self { 23 | let work_mode = hal_mode_to_pac(mode); 24 | let frame_format = frame_format_to_pac(frame_format); 25 | let tmod = crate::pac::spi0::ctrlr0::TMOD_A::TRANS_RECV; // todo other modes 26 | let endian = endian as u32; 27 | let data_bit_length = 8; // todo more length 28 | let _ = clock; // todo 29 | unsafe { 30 | // no interrupts for now 31 | spi.imr.write(|w| w.bits(0x00)); 32 | // no dma for now 33 | spi.dmacr.write(|w| w.bits(0x00)); 34 | spi.dmatdlr.write(|w| w.bits(0x10)); 35 | spi.dmardlr.write(|w| w.bits(0x00)); 36 | // no slave access for now 37 | spi.ser.write(|w| w.bits(0x00)); 38 | spi.ssienr.write(|w| w.bits(0x00)); 39 | // set control registers 40 | spi.ctrlr0.write(|w| { 41 | w.work_mode() 42 | .variant(work_mode) 43 | .tmod() 44 | .variant(tmod) 45 | .frame_format() 46 | .variant(frame_format) 47 | .data_length() 48 | .bits(data_bit_length - 1) 49 | }); 50 | spi.spi_ctrlr0.reset(); // standard 51 | spi.endian.write(|w| w.bits(endian)); 52 | } 53 | // enable APB0 bus 54 | apb0.enable(); 55 | // enable peripheral via sysctl 56 | sysctl::clk_en_peri().modify(|_r, w| w.spi0_clk_en().set_bit()); 57 | Spi { spi } 58 | } 59 | 60 | #[inline] 61 | pub fn release(self) -> SPI0 { 62 | // power off 63 | sysctl::clk_en_peri().modify(|_r, w| w.spi0_clk_en().clear_bit()); 64 | self.spi 65 | } 66 | } 67 | 68 | impl embedded_hal::spi::ErrorType for Spi { 69 | type Error = core::convert::Infallible; 70 | } 71 | 72 | impl embedded_hal::spi::SpiBus for Spi { 73 | /// Reads the word stored in the shift register 74 | /// 75 | /// **NOTE** A word must be sent to the slave before attempting to call this 76 | /// method. 77 | fn read(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> { 78 | todo!() 79 | } 80 | 81 | fn write(&mut self, _words: &[u8]) -> Result<(), Self::Error> { 82 | todo!() 83 | } 84 | 85 | fn transfer(&mut self, _read: &mut [u8], _write: &[u8]) -> Result<(), Self::Error> { 86 | todo!() 87 | } 88 | 89 | fn transfer_in_place(&mut self, _words: &mut [u8]) -> Result<(), Self::Error> { 90 | todo!() 91 | } 92 | 93 | fn flush(&mut self) -> Result<(), Self::Error> { 94 | todo!() 95 | } 96 | } 97 | 98 | #[derive(Clone, Copy, PartialEq, Eq)] 99 | pub enum FrameFormat { 100 | Standard, 101 | Dual, 102 | Quad, 103 | Octal, 104 | } 105 | #[derive(Clone, Copy, PartialEq, Eq)] 106 | #[repr(u32)] 107 | pub enum Endian { 108 | Little = 0, 109 | Big = 1, 110 | } 111 | 112 | #[inline] 113 | fn hal_mode_to_pac(mode: Mode) -> crate::pac::spi0::ctrlr0::WORK_MODE_A { 114 | use crate::pac::spi0::ctrlr0::WORK_MODE_A; 115 | use {Phase::*, Polarity::*}; 116 | match (mode.polarity, mode.phase) { 117 | (IdleLow, CaptureOnFirstTransition) => WORK_MODE_A::MODE0, 118 | (IdleLow, CaptureOnSecondTransition) => WORK_MODE_A::MODE1, 119 | (IdleHigh, CaptureOnFirstTransition) => WORK_MODE_A::MODE2, 120 | (IdleHigh, CaptureOnSecondTransition) => WORK_MODE_A::MODE3, 121 | } 122 | } 123 | 124 | #[inline] 125 | fn frame_format_to_pac(frame_format: FrameFormat) -> crate::pac::spi0::ctrlr0::FRAME_FORMAT_A { 126 | use crate::pac::spi0::ctrlr0::FRAME_FORMAT_A; 127 | match frame_format { 128 | FrameFormat::Standard => FRAME_FORMAT_A::STANDARD, 129 | FrameFormat::Dual => FRAME_FORMAT_A::DUAL, 130 | FrameFormat::Quad => FRAME_FORMAT_A::QUAD, 131 | FrameFormat::Octal => FRAME_FORMAT_A::OCTAL, 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/sysctl.rs: -------------------------------------------------------------------------------- 1 | //! (TODO) System Controller (SYSCTL) 2 | 3 | use crate::clock::Clocks; 4 | use crate::pac::{sysctl, SYSCTL}; 5 | use crate::time::Hertz; 6 | use core::sync::atomic::Ordering; 7 | 8 | const CLOCK_FREQ_IN0: u32 = 26_000_000; 9 | 10 | pub(crate) fn sysctl<'a>() -> &'a sysctl::RegisterBlock { 11 | unsafe { &*(SYSCTL::ptr()) } 12 | } 13 | 14 | pub(crate) fn clk_en_cent<'a>() -> &'a sysctl::CLK_EN_CENT { 15 | &sysctl().clk_en_cent 16 | } 17 | 18 | pub(crate) fn clk_en_peri<'a>() -> &'a sysctl::CLK_EN_PERI { 19 | &sysctl().clk_en_peri 20 | } 21 | 22 | pub(crate) fn peri_reset<'a>() -> &'a sysctl::PERI_RESET { 23 | &sysctl().peri_reset 24 | } 25 | 26 | /// Accept freq_in as the input frequency, 27 | /// and try to find a set of parameters (nr, od, nf), 28 | /// which results in a frequency as near as possible to freq 29 | /// note for a PLL: 30 | /// freq_out = freq_in / nr * nf / od 31 | /// The reason why we don't port the complex config algorithm from the 32 | /// official C language SDK is that doing floating number arithmetics 33 | /// efficiently in no_std rust now is currently not very convenient 34 | fn calculate_pll_config(freq_in: u32, freq: u32) -> (u8, u8, u8) { 35 | // finding a set of (nr, od, nf) which minify abs(freq * nr * od - freq_in * nf) 36 | // nr, od is in [0b1, 0b10_000], nr * od is in [0b1, 0b100_000_000] 37 | // nf is in [0b1, 0b1_000_000] 38 | 39 | // for archiving a higher accuracy, we want the nr * od as large as possible 40 | // use binary search to find the largest nr_od which freq <= freq_in * 0b1_000_000 / nr_od 41 | let mut left = 1; 42 | let mut right = 0b1_0000 * 0b1_0000 + 1; 43 | while left + 1 < right { 44 | let mid = (left + right) / 2; 45 | let max_freq = freq_in * 0b100_0000 / mid; 46 | if freq >= max_freq { 47 | // in [left, mid) 48 | right = mid; 49 | } else { 50 | // in [mid, right) 51 | left = mid; 52 | } 53 | } 54 | let nr_od = left; 55 | // so we got nf 56 | let nf = freq * nr_od / freq_in; 57 | let nf = nf.min(0b100_0000) as u8; 58 | 59 | // decompose nr_od 60 | for nr in 1..=0b1_0000 { 61 | if (nr_od / nr) * nr == nr_od { 62 | return (nr as u8, (nr_od / nr) as u8, nf); 63 | } 64 | } 65 | unreachable!() 66 | } 67 | 68 | pub trait SysctlExt { 69 | fn constrain(self) -> Parts; 70 | } 71 | 72 | impl SysctlExt for SYSCTL { 73 | fn constrain(self) -> Parts { 74 | Parts { 75 | aclk: ACLK { _ownership: () }, 76 | apb0: APB0 { _ownership: () }, 77 | pll0: PLL0 { _ownership: () }, 78 | } 79 | } 80 | } 81 | 82 | // ref: sysctl.c 83 | pub struct Parts { 84 | /// entry for controlling the frequency of aclk 85 | pub aclk: ACLK, 86 | /// entry for controlling the enable/disable/frequency of pll0 87 | pub pll0: PLL0, 88 | /// entry for controlling the enable/disable/frequency of apb0 89 | pub apb0: APB0, 90 | // todo: SRAM, APB-bus, ROM, DMA, AI, PLL1, PLL2, APB1, APB2 91 | } 92 | 93 | impl Parts { 94 | pub fn clocks(&self) -> Clocks { 95 | Clocks { 96 | aclk: self.aclk.get_frequency(), 97 | apb0: self.apb0.get_frequency(), 98 | } 99 | } 100 | } 101 | 102 | pub struct APB0 { 103 | _ownership: (), 104 | } 105 | 106 | impl APB0 { 107 | pub(crate) fn enable(&mut self) { 108 | clk_en_cent().modify(|_r, w| w.apb0_clk_en().set_bit()); 109 | } 110 | 111 | pub fn set_frequency(&mut self, expected_freq: impl Into) -> Hertz { 112 | let aclk = ACLK::steal(); 113 | let aclk_frequency = aclk.get_frequency().0 as i64; 114 | // apb0_frequency = aclk_frequency / (apb0_clk_sel + 1) 115 | let apb0_clk_sel = (aclk_frequency / expected_freq.into().0 as i64 - 1) 116 | .max(0) 117 | .min(0b111) as u8; 118 | unsafe { 119 | sysctl() 120 | .clk_sel0 121 | .modify(|_, w| w.apb0_clk_sel().bits(apb0_clk_sel)); 122 | } 123 | Hertz(aclk_frequency as u32 / (apb0_clk_sel as u32 + 1)) 124 | } 125 | 126 | pub fn get_frequency(&self) -> Hertz { 127 | let aclk = ACLK::steal(); 128 | let aclk_frequency = aclk.get_frequency().0 as i64; 129 | let apb0_clk_sel = sysctl().clk_sel0.read().apb0_clk_sel().bits(); 130 | Hertz(aclk_frequency as u32 / (apb0_clk_sel as u32 + 1)) 131 | } 132 | } 133 | 134 | // pub struct APB1 { 135 | // _ownership: () 136 | // } 137 | 138 | // pub struct APB2 { 139 | // _ownership: () 140 | // } 141 | 142 | /// PLL0, which source is CLOCK_FREQ_IN0, 143 | /// and the output can be used on ACLK(CPU), SPIs, etc. 144 | pub struct PLL0 { 145 | _ownership: (), 146 | } 147 | 148 | impl PLL0 { 149 | pub(crate) fn steal() -> Self { 150 | PLL0 { _ownership: () } 151 | } 152 | 153 | #[inline(always)] 154 | fn is_locked(&self) -> bool { 155 | sysctl().pll_lock.read().pll_lock0() == 0b11 156 | } 157 | 158 | fn lock(&mut self) { 159 | while !self.is_locked() { 160 | sysctl() 161 | .pll_lock 162 | .modify(|_, w| w.pll_slip_clear0().set_bit()) 163 | } 164 | } 165 | 166 | #[inline(always)] 167 | fn reset(&mut self) { 168 | sysctl().pll0.modify(|_, w| w.reset().clear_bit()); 169 | sysctl().pll0.modify(|_, w| w.reset().set_bit()); 170 | core::sync::atomic::compiler_fence(Ordering::SeqCst); 171 | core::sync::atomic::compiler_fence(Ordering::SeqCst); 172 | sysctl().pll0.modify(|_, w| w.reset().clear_bit()); 173 | } 174 | 175 | /// enable PLL0 176 | pub fn enable(&mut self) { 177 | sysctl() 178 | .pll0 179 | .modify(|_, w| w.bypass().clear_bit().pwrd().set_bit()); 180 | self.reset(); 181 | self.lock(); 182 | sysctl().pll0.modify(|_, w| w.out_en().set_bit()); 183 | } 184 | 185 | /// disable PLL0 186 | /// use with caution: PLL0 can be used as source clock of ACLK (so also CPU), 187 | /// if you want to disable PLL0, please make the cpu use external clock first 188 | pub fn disable(&mut self) { 189 | sysctl() 190 | .pll0 191 | .modify(|_, w| w.bypass().set_bit().pwrd().clear_bit().out_en().clear_bit()); 192 | } 193 | 194 | /// Set frequency of PLL0 195 | /// Will set the frequency of PLL0 as close to frequency as possible 196 | /// Return the real frequency of the PLL0 197 | pub fn set_frequency(&mut self, frequency: impl Into) -> Hertz { 198 | let is_aclk_using = sysctl().clk_sel0.read().aclk_sel().bit(); 199 | if is_aclk_using { 200 | sysctl().clk_sel0.modify(|_, w| w.aclk_sel().clear_bit()); 201 | } 202 | self.disable(); 203 | let (nr, od, nf) = calculate_pll_config(CLOCK_FREQ_IN0, frequency.into().0); 204 | unsafe { 205 | sysctl().pll0.modify(|_, w| { 206 | w.clkr() 207 | .bits(nr - 1) 208 | .clkf() 209 | .bits(nf - 1) 210 | .clkod() 211 | .bits(od - 1) 212 | .bwadj() 213 | .bits(nf - 1) 214 | }); 215 | } 216 | self.enable(); 217 | // recover aclk_sel 218 | if is_aclk_using { 219 | sysctl().clk_sel0.modify(|_, w| w.aclk_sel().set_bit()); 220 | } 221 | Hertz(CLOCK_FREQ_IN0 / nr as u32 * nf as u32 / od as u32) 222 | } 223 | 224 | /// Return the frequency of PLL0 225 | pub fn get_frequency(&self) -> Hertz { 226 | let nr = sysctl().pll0.read().clkr().bits() + 1; 227 | let nf = sysctl().pll0.read().clkf().bits() + 1; 228 | let od = sysctl().pll0.read().clkod().bits() + 1; 229 | Hertz(CLOCK_FREQ_IN0 / nr as u32 * nf as u32 / od as u32) 230 | } 231 | } 232 | 233 | pub struct ACLK { 234 | _ownership: (), 235 | } 236 | 237 | /// ACLK clock frequency control 238 | impl ACLK { 239 | pub fn steal() -> Self { 240 | ACLK { _ownership: () } 241 | } 242 | 243 | /// make ACLK use external clock, ie. CLOCK_FREQ_IN0 244 | pub(crate) fn use_external(&mut self) { 245 | sysctl().clk_sel0.modify(|_, w| w.aclk_sel().clear_bit()); 246 | } 247 | 248 | /// Return whether the ACLK is using external clock 249 | pub fn is_using_external(&self) -> bool { 250 | !sysctl().clk_sel0.read().aclk_sel().bit() 251 | } 252 | 253 | /// make ACLK use pll0 clock, with aclk_divider_sel 254 | pub fn use_pll0(&mut self, aclk_divider_sel: u8) { 255 | unsafe { 256 | sysctl().clk_sel0.modify(|_, w| { 257 | w.aclk_divider_sel() 258 | .bits(aclk_divider_sel) 259 | .aclk_sel() 260 | .set_bit() 261 | }); 262 | } 263 | } 264 | 265 | /// Set the frequency of ACLK 266 | /// if frequency == CLOCK_FREQ_IN0, use external clock directly 267 | /// else frequency settings here are based on existing settings on PLL0 268 | /// We won't adjust PLL0 here because there are so many devices based on it. 269 | pub fn set_frequency(&mut self, expected_freq: impl Into) -> Hertz { 270 | let expected_freq = expected_freq.into().0; 271 | if expected_freq == CLOCK_FREQ_IN0 { 272 | self.use_external(); 273 | Hertz(CLOCK_FREQ_IN0) 274 | } else { 275 | // aclk = pll0 / (2 << aclk_divider_sel) 276 | let pll0 = PLL0::steal().get_frequency().0; 277 | let mut aclk_divider_sel = 0u8; 278 | // aclk_divider_sel is 2 bits 279 | if expected_freq < pll0 / (2 << 0b11) { 280 | aclk_divider_sel = 0b11; 281 | } else { 282 | for i in 0b00u8..0b11 { 283 | if pll0 / (2 << i) <= expected_freq { 284 | aclk_divider_sel = i; 285 | break; 286 | } 287 | } 288 | } 289 | self.use_pll0(aclk_divider_sel); 290 | Hertz(pll0 / (2 << aclk_divider_sel)) 291 | } 292 | } 293 | 294 | /// Get the frequency of ACLK 295 | pub fn get_frequency(&self) -> Hertz { 296 | if self.is_using_external() { 297 | Hertz(CLOCK_FREQ_IN0) 298 | } else { 299 | let pll0 = PLL0::steal().get_frequency().0; 300 | let aclk_divider_sel = sysctl().clk_sel0.read().aclk_divider_sel().bits(); 301 | Hertz(pll0 / (2 << aclk_divider_sel)) 302 | } 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /src/time.rs: -------------------------------------------------------------------------------- 1 | //! Time units 2 | 3 | /// Bits per second 4 | #[derive(Clone, Copy)] 5 | pub struct Bps(pub u32); 6 | 7 | /// Hertz 8 | #[derive(Clone, Copy)] 9 | pub struct Hertz(pub u32); 10 | 11 | /// KiloHertz 12 | #[derive(Clone, Copy)] 13 | pub struct KiloHertz(pub u32); 14 | 15 | /// MegaHertz 16 | #[derive(Clone, Copy)] 17 | pub struct MegaHertz(pub u32); 18 | 19 | /// Extension trait that adds convenience methods to the `u32` type 20 | pub trait U32Ext { 21 | /// Wrap in `Bps` 22 | fn bps(self) -> Bps; 23 | 24 | /// Wrap in `Hertz` 25 | fn hz(self) -> Hertz; 26 | 27 | /// Wrap in `KiloHertz` 28 | fn khz(self) -> KiloHertz; 29 | 30 | /// Wrap in `MegaHertz` 31 | fn mhz(self) -> MegaHertz; 32 | } 33 | 34 | impl U32Ext for u32 { 35 | fn bps(self) -> Bps { 36 | Bps(self) 37 | } 38 | 39 | fn hz(self) -> Hertz { 40 | Hertz(self) 41 | } 42 | 43 | fn khz(self) -> KiloHertz { 44 | KiloHertz(self) 45 | } 46 | 47 | fn mhz(self) -> MegaHertz { 48 | MegaHertz(self) 49 | } 50 | } 51 | 52 | impl From for Hertz { 53 | fn from(src: KiloHertz) -> Hertz { 54 | Hertz(src.0 * 1_000) 55 | } 56 | } 57 | 58 | impl From for Hertz { 59 | fn from(src: MegaHertz) -> Hertz { 60 | Hertz(src.0 * 1_000_000) 61 | } 62 | } 63 | 64 | impl From for KiloHertz { 65 | fn from(src: MegaHertz) -> KiloHertz { 66 | KiloHertz(src.0 * 1_000) 67 | } 68 | } 69 | --------------------------------------------------------------------------------