├── .cargo └── config ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── README.md ├── build.rs ├── examples ├── blinky.rs ├── gpio-console.rs ├── gpiohs-interrupt.rs ├── interrupt.rs ├── multi-core.rs ├── sdcard.rs └── serial-console.rs ├── gdb_init ├── memory.x ├── openocd.cfg └── src └── main.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | # According to Section 3.1, Kendryte K210 Datasheet, 2 | # K210 chip has two RV64IMAFDC (RV64GC) cores. 3 | # We need `riscv64gc` targets for this chip. 4 | 5 | [target.riscv64gc-unknown-none-elf] 6 | #runner = "riscv64-unknown-elf-gdb -x gdb_init" 7 | runner = "../k210-run --flash" 8 | rustflags = [ 9 | "-C", "link-arg=-Tmemory.x", 10 | "-C", "link-arg=-Tlink.x", 11 | ] 12 | 13 | [build] 14 | target = "riscv64gc-unknown-none-elf" 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk -------------------------------------------------------------------------------- /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-example" 3 | version = "0.1.1" 4 | authors = ["The RISC-V Team "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | panic-halt = "0.2.0" 9 | riscv = "0.6.0" 10 | riscv-rt = "0.8.0" 11 | k210-hal = "0.2.0" 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `k210-example` 2 | 3 | > Example project for K210 SoC 4 | 5 | This project is developed and maintained by the [RISC-V team][team]. 6 | 7 | ## Getting started 8 | 9 | Start openocd: 10 | 11 | openocd -f dp_busblaster.cfg -f openocd.cfg 12 | 13 | Run the example: 14 | 15 | cargo run 16 | 17 | 18 | ## License 19 | 20 | Copyright 2019 [RISC-V team][team] 21 | 22 | Permission to use, copy, modify, and/or distribute this software for any 23 | purpose with or without fee is hereby granted, provided that the above 24 | copyright notice and this permission notice appear in all copies. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 27 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 28 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 29 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 30 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 31 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 32 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 | 34 | ## Code of Conduct 35 | 36 | Contribution to this crate is organized under the terms of the [Rust Code of 37 | Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises 38 | to intervene to uphold that code of conduct. 39 | 40 | [CoC]: CODE_OF_CONDUCT.md 41 | [team]: https://github.com/rust-embedded/wg#the-risc-v-team 42 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs}; 2 | use std::path::PathBuf; 3 | use std::io::Write; 4 | 5 | fn main() { 6 | // Put the linker script somewhere the linker can find it 7 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); 8 | println!("cargo:rustc-link-search={}", out_dir.display()); 9 | 10 | fs::File::create(out_dir.join("memory.x")).unwrap() 11 | .write_all(include_bytes!("memory.x")).unwrap(); 12 | println!("cargo:rerun-if-changed=memory.x"); 13 | } 14 | -------------------------------------------------------------------------------- /examples/blinky.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | use k210_hal::{prelude::*, fpioa, pac, gpio::Gpio}; 6 | 7 | #[riscv_rt::entry] 8 | fn main() -> ! { 9 | let p = pac::Peripherals::take().unwrap(); 10 | 11 | let mut sysctl = p.SYSCTL.constrain(); 12 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 13 | let gpio = p.GPIO.split(&mut sysctl.apb0); 14 | let io14 = fpioa.io14.into_function(fpioa::GPIO6); 15 | let mut blue = Gpio::new(gpio.gpio6, io14).into_push_pull_output(); 16 | 17 | blue.try_set_low().ok(); 18 | 19 | let mut last_update = riscv::register::mcycle::read(); 20 | loop { 21 | let cur = riscv::register::mcycle::read(); 22 | if cur - last_update >= 100_000_000 { 23 | last_update = cur; 24 | 25 | blue.try_toggle().ok(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/gpio-console.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | use k210_hal::{prelude::*, fpioa, pac, gpio::Gpio, stdout::Stdout}; 6 | 7 | #[riscv_rt::entry] 8 | fn main() -> ! { 9 | let p = pac::Peripherals::take().unwrap(); 10 | 11 | let mut sysctl = p.SYSCTL.constrain(); 12 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 13 | let gpio = p.GPIO.split(&mut sysctl.apb0); 14 | let gpiohs = p.GPIOHS.split(); 15 | 16 | // Configure clocks (TODO) 17 | let clocks = k210_hal::clock::Clocks::new(); 18 | 19 | // prepare pins 20 | let _uarths_tx = fpioa.io5.into_function(fpioa::UARTHS_TX); 21 | 22 | // let boot_button = Gpio::new( 23 | // gpio.gpio2, 24 | // fpioa.io16.into_function(fpioa::GPIO2) 25 | // ).into_pull_up_input(); 26 | let io14 = fpioa.io14.into_function(fpioa::GPIO6); 27 | let mut blue = Gpio::new(gpio.gpio6, io14).into_push_pull_output(); 28 | 29 | // Configure UART 30 | let serial = p.UARTHS.configure( 31 | 115_200.bps(), 32 | &clocks 33 | ); 34 | let (mut tx, _rx) = serial.split(); 35 | 36 | let mut stdout = Stdout(&mut tx); 37 | 38 | writeln!(stdout, "Hello, Rust!").ok(); 39 | 40 | unsafe { &*pac::GPIO::ptr() }.source.write(|w| unsafe { w.bits(0xaa) }); 41 | loop { 42 | for i in 8..16 { 43 | let io = unsafe { &*pac::FPIOA::ptr() }.io[i].read(); 44 | writeln!(stdout, 45 | "[{}] CH {}, DS {:02X}, OE {}, OEI {}, DO {}, DOI {}, PU {}, PD {}, SL {}, IE {}, IEI {}, DII {}, ST {}, PA {}", 46 | i, io.ch_sel().bits(), io.ds().bits(), io.oe_en().bit(), io.oe_inv().bit(), 47 | io.do_sel().bit(), io.do_inv().bit(), io.pu().bit(), io.pd().bit(), 48 | io.sl().bit(), io.ie_en().bit(), io.ie_inv().bit(), io.di_inv().bit(), io.st().bit(), io.pad_di().bit() 49 | ).ok(); 50 | } 51 | let data_output = unsafe { &*pac::GPIO::ptr() }.data_output.read().bits(); 52 | let direction = unsafe { &*pac::GPIO::ptr() }.direction.read().bits(); 53 | let source = unsafe { &*pac::GPIO::ptr() }.source.read().bits(); 54 | let data_input = unsafe { &*pac::GPIO::ptr() }.data_input.read().bits(); 55 | let sync_level = unsafe { &*pac::GPIO::ptr() }.sync_level.read().bits(); 56 | let id_code = unsafe { &*pac::GPIO::ptr() }.id_code.read().bits(); 57 | writeln!(stdout, 58 | "O {:08b}, D {:08b}, S {:08b}, I {:08b}, SY {:08b}, ID 0x{:08X}", 59 | data_output, direction, source, data_input, sync_level, id_code 60 | ).ok(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /examples/gpiohs-interrupt.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use k210_hal::{prelude::*, pac::{self, Interrupt}, plic::*, fpioa, gpiohs::Edge, stdout::Stdout}; 5 | use panic_halt as _; 6 | use riscv::register::{mie,mstatus,mhartid,mcause}; 7 | use core::sync::atomic::{AtomicBool, Ordering}; 8 | 9 | static INTR: AtomicBool = AtomicBool::new(false); 10 | 11 | #[derive(Debug, Copy, Clone)] 12 | struct IntrInfo { 13 | hart_id: usize, 14 | cause: usize, 15 | } 16 | 17 | static mut INTR_INFO: Option = None; 18 | 19 | #[export_name = "MachineExternal"] 20 | fn my_trap_handler() { 21 | let hart_id = mhartid::read(); 22 | let threshold = pac::PLIC::get_threshold(hart_id); 23 | 24 | let irq = pac::PLIC::claim(hart_id).unwrap(); 25 | let prio = pac::PLIC::get_priority(irq); 26 | unsafe { 27 | pac::PLIC::set_threshold(hart_id, prio); 28 | mie::clear_msoft(); 29 | mie::clear_mtimer(); 30 | } 31 | 32 | // actual handle process starts 33 | let stdout = unsafe { &mut *SHARED_STDOUT.as_mut_ptr() }; 34 | let gpiohs0 = unsafe { &mut *GPIOHS0.as_mut_ptr() }; 35 | 36 | let cause = mcause::read().bits(); 37 | 38 | writeln!(stdout, 39 | "[Interrupt] Hart #{}, Cause: {:016X}, Edges: {:?}", 40 | hart_id, cause, gpiohs0.check_edges() 41 | ).ok(); 42 | 43 | unsafe { INTR_INFO = Some(IntrInfo { hart_id, cause }); } 44 | 45 | INTR.store(true, Ordering::SeqCst); 46 | 47 | gpiohs0.clear_interrupt_pending_bits(); 48 | // actual handle process ends 49 | 50 | unsafe { 51 | mie::set_msoft(); 52 | mie::set_mtimer(); 53 | pac::PLIC::set_threshold(hart_id, threshold); 54 | } 55 | pac::PLIC::complete(hart_id, irq); 56 | } 57 | 58 | static mut SHARED_STDOUT: core::mem::MaybeUninit< 59 | k210_hal::stdout::Stdout> 60 | > = core::mem::MaybeUninit::uninit(); 61 | static mut GPIOHS0: core::mem::MaybeUninit< 62 | k210_hal::gpiohs::Gpiohs0> 63 | > = core::mem::MaybeUninit::uninit(); 64 | 65 | #[riscv_rt::entry] 66 | fn main() -> ! { 67 | let p = pac::Peripherals::take().unwrap(); 68 | 69 | let mut sysctl = p.SYSCTL.constrain(); 70 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 71 | let gpiohs = p.GPIOHS.split(); 72 | fpioa.io16.into_function(fpioa::GPIOHS0); 73 | let mut boot = gpiohs.gpiohs0.into_pull_up_input(); 74 | 75 | // Configure clocks (TODO) 76 | let clocks = k210_hal::clock::Clocks::new(); 77 | 78 | // Configure UART 79 | let serial = p.UARTHS.configure(115_200.bps(), &clocks); 80 | let (mut tx, _) = serial.split(); 81 | 82 | let mut stdout = Stdout(&mut tx); 83 | 84 | writeln!(stdout, "This code is running on hart {}", mhartid::read()).ok(); 85 | 86 | writeln!(stdout, "Initializing interrupts").ok(); 87 | let hart_id = mhartid::read(); 88 | unsafe { 89 | // set PLIC threshold for current core 90 | pac::PLIC::set_threshold(hart_id, Priority::P0); 91 | // Enable interrupts in general 92 | mstatus::set_mie(); 93 | // Set the Machine-External bit in MIE 94 | mie::set_mext(); 95 | } 96 | 97 | writeln!(stdout, "Enabling interrupt trigger for GPIOHS0").ok(); 98 | boot.trigger_on_edge(Edge::RISING | Edge::FALLING); 99 | 100 | // enable IRQ for gpiohs0 interrupt 101 | writeln!(stdout, "Enabling IRQ for GPIOHS0").ok(); 102 | unsafe { 103 | pac::PLIC::set_priority(Interrupt::GPIOHS0, Priority::P1); 104 | pac::PLIC::unmask(hart_id, Interrupt::GPIOHS0); 105 | } 106 | 107 | writeln!(stdout, "Configuration finished!").ok(); 108 | 109 | loop { 110 | writeln!(stdout, "Waiting for interrupt").ok(); 111 | unsafe { riscv::asm::wfi(); } 112 | 113 | while !INTR.load(Ordering::SeqCst) { 114 | use core::sync::atomic::{self, Ordering}; 115 | atomic::compiler_fence(Ordering::SeqCst); 116 | } 117 | INTR.store(false, Ordering::SeqCst); 118 | 119 | writeln!(stdout, 120 | "Interrupt was triggered! hart_id: {}, cause: {:16X}", 121 | unsafe { INTR_INFO }.unwrap().hart_id, 122 | unsafe { INTR_INFO }.unwrap().cause, 123 | ).ok(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /examples/interrupt.rs: -------------------------------------------------------------------------------- 1 | // Ref: https://github.com/laanwj/k210-sdk-stuff/blob/master/rust/interrupt/src/main.rs 2 | #![feature(llvm_asm)] 3 | #![no_std] 4 | #![no_main] 5 | 6 | use k210_hal::{prelude::*, pac, clint::msip, stdout::Stdout}; 7 | use panic_halt as _; 8 | use riscv::register::{mie,mstatus,mhartid,/*mvendorid,marchid,mimpid,*/mcause}; 9 | use core::sync::atomic::{AtomicBool, Ordering}; 10 | // use core::ptr; 11 | 12 | // fn peek(addr: u64) -> T { 13 | // unsafe { ptr::read_volatile(addr as *const T) } 14 | // } 15 | 16 | static INTR: AtomicBool = AtomicBool::new(false); 17 | 18 | #[derive(Debug, Copy, Clone)] 19 | struct IntrInfo { 20 | hart_id: usize, 21 | cause: usize, 22 | } 23 | 24 | static mut INTR_INFO: Option = None; 25 | 26 | #[export_name = "DefaultHandler"] 27 | fn my_trap_handler() { 28 | let hart_id = mhartid::read(); 29 | let cause = mcause::read().bits(); 30 | 31 | unsafe { INTR_INFO = Some(IntrInfo { hart_id, cause }); } 32 | 33 | INTR.store(true, Ordering::SeqCst); 34 | 35 | msip::clear_ipi(hart_id); 36 | } 37 | 38 | #[riscv_rt::entry] 39 | fn main() -> ! { 40 | let hart_id = mhartid::read(); 41 | 42 | static mut SHARED_TX: Option> = None; 45 | 46 | if hart_id == 0 { 47 | let p = pac::Peripherals::take().unwrap(); 48 | 49 | //configure_fpioa(p.FPIOA); 50 | 51 | // Configure clocks (TODO) 52 | let clocks = k210_hal::clock::Clocks::new(); 53 | 54 | // Configure UART 55 | let serial = p.UARTHS.configure(115_200.bps(), &clocks); 56 | let (tx, _) = serial.split(); 57 | 58 | unsafe { 59 | SHARED_TX.replace(tx); 60 | } 61 | } 62 | 63 | // Super-unsafe UART sharing! 64 | let tx = unsafe { 65 | SHARED_TX.as_mut().unwrap() 66 | }; 67 | let mut stdout = Stdout(tx); 68 | 69 | if hart_id == 1 { 70 | // Add delay for hart 1 71 | for _ in 0..100000 { 72 | let _ = mhartid::read(); 73 | } 74 | } 75 | 76 | // writeln!(stdout, "Hello! Some CPU information!").unwrap(); 77 | // writeln!(stdout, " mvendorid {:?}", mvendorid::read()).unwrap(); 78 | // writeln!(stdout, " marchid {:?}", marchid::read()).unwrap(); 79 | // writeln!(stdout, " mimpid {:?}", mimpid::read()).unwrap(); 80 | writeln!(stdout, "This code is running on hart {}", mhartid::read()).unwrap(); 81 | 82 | writeln!(stdout, "Enabling interrupts").unwrap(); 83 | 84 | unsafe { 85 | // Enable interrupts in general 86 | mstatus::set_mie(); 87 | // Set the Machine-Software bit in MIE 88 | mie::set_msoft(); 89 | // Set the Machine-External bit in MIE 90 | mie::set_mext(); 91 | } 92 | 93 | writeln!(stdout, "Generate IPI for core {} !", hart_id).unwrap(); 94 | msip::set_ipi(hart_id); 95 | 96 | writeln!(stdout, "Waiting for interrupt").unwrap(); 97 | while !INTR.load(Ordering::SeqCst) { 98 | } 99 | INTR.store(false, Ordering::SeqCst); 100 | writeln!(stdout, 101 | "Interrupt was triggered! hart_id: {:16X}, cause: {:16X}", 102 | unsafe { INTR_INFO }.unwrap().hart_id, 103 | unsafe { INTR_INFO }.unwrap().cause, 104 | ).unwrap(); 105 | 106 | 107 | if hart_id == 0 { 108 | writeln!(stdout, "Waking other harts...").unwrap(); 109 | // wake hart 1 110 | msip::set_ipi(1); 111 | } 112 | 113 | loop { unsafe { riscv::asm::wfi(); } } 114 | } 115 | 116 | #[export_name = "_mp_hook"] 117 | pub extern "Rust" fn user_mp_hook() -> bool { 118 | use riscv::register::/*{mie, */mip/*}*/; 119 | use riscv::asm::wfi; 120 | 121 | let hart_id = mhartid::read(); 122 | if hart_id == 0 { 123 | true 124 | } else { 125 | 126 | unsafe { 127 | msip::set_ipi(hart_id); 128 | 129 | // Start listening for software interrupts 130 | mie::set_msoft(); 131 | 132 | loop { 133 | wfi(); 134 | if mip::read().msoft() { 135 | break; 136 | } 137 | } 138 | 139 | // Stop listening for software interrupts 140 | mie::clear_msoft(); 141 | 142 | // Clear IPI 143 | msip::clear_ipi(hart_id); 144 | } 145 | false 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /examples/multi-core.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | extern crate panic_halt; 5 | 6 | use riscv::register::mhartid; 7 | use riscv_rt::entry; 8 | use k210_hal::prelude::*; 9 | use k210_hal::pac::{Peripherals, UARTHS, CLINT}; 10 | use k210_hal::stdout::Stdout; 11 | use k210_hal::serial::Tx; 12 | 13 | #[export_name = "_mp_hook"] 14 | pub extern "Rust" fn user_mp_hook() -> bool { 15 | use riscv::register::{mie, mip}; 16 | use riscv::asm::wfi; 17 | 18 | let hartid = mhartid::read(); 19 | if hartid == 0 { 20 | true 21 | } else { 22 | let clint = unsafe { &*CLINT::ptr() }; 23 | let msip = &clint.msip[hartid]; 24 | 25 | unsafe { 26 | // Clear IPI 27 | msip.write(|w| w.bits(0)); 28 | 29 | // Start listening for software interrupts 30 | mie::set_msoft(); 31 | 32 | loop { 33 | wfi(); 34 | if mip::read().msoft() { 35 | break; 36 | } 37 | } 38 | 39 | // Stop listening for software interrupts 40 | mie::clear_msoft(); 41 | 42 | // Clear IPI 43 | msip.write(|w| w.bits(0)); 44 | } 45 | false 46 | } 47 | } 48 | 49 | pub fn wake_hart(hartid: usize) { 50 | unsafe { 51 | let clint = &*CLINT::ptr(); 52 | clint.msip[hartid].write(|w| w.bits(1)); 53 | } 54 | } 55 | 56 | 57 | #[entry] 58 | fn main() -> ! { 59 | let hartid = mhartid::read(); 60 | 61 | static mut SHARED_TX: Option> = None; 62 | 63 | if hartid == 0 { 64 | let p = Peripherals::take().unwrap(); 65 | 66 | //configure_fpioa(p.FPIOA); 67 | 68 | // Configure clocks (TODO) 69 | let clocks = k210_hal::clock::Clocks::new(); 70 | 71 | // Configure UART 72 | let serial = p.UARTHS.configure(115_200.bps(), &clocks); 73 | let (tx, _) = serial.split(); 74 | 75 | unsafe { 76 | SHARED_TX.replace(tx); 77 | } 78 | } 79 | 80 | // Super-unsafe UART sharing! 81 | let tx = unsafe { 82 | SHARED_TX.as_mut().unwrap() 83 | }; 84 | let mut stdout = Stdout(tx); 85 | 86 | if hartid == 1 { 87 | // Add delay for hart 1 88 | for _ in 0..100000 { 89 | let _ = mhartid::read(); 90 | } 91 | } 92 | 93 | writeln!(stdout, "Hello, Rust from hart {}", hartid).unwrap(); 94 | if hartid == 0 { 95 | writeln!(stdout, "Waking other harts...").unwrap(); 96 | wake_hart(1); 97 | } 98 | 99 | loop { } 100 | } 101 | -------------------------------------------------------------------------------- /examples/sdcard.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | use k210_hal::{prelude::*, fpioa, pac, gpio::Gpio}; 6 | 7 | #[riscv_rt::entry] 8 | fn main() -> ! { 9 | // todo 10 | let p = pac::Peripherals::take().unwrap(); 11 | 12 | let mut sysctl = p.SYSCTL.constrain(); 13 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 14 | let gpio = p.GPIO.split(&mut sysctl.apb0); 15 | let io14 = fpioa.io14.into_function(fpioa::GPIO6); 16 | let mut blue = Gpio::new(gpio.gpio6, io14).into_push_pull_output(); 17 | 18 | blue.try_set_low().ok(); 19 | 20 | let mut last_update = riscv::register::mcycle::read(); 21 | loop { 22 | let cur = riscv::register::mcycle::read(); 23 | if cur - last_update >= 100_000_000 { 24 | last_update = cur; 25 | 26 | blue.try_toggle().ok(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/serial-console.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_halt as _; 5 | use k210_hal::{prelude::*, fpioa, pac, stdout::Stdout}; 6 | 7 | #[riscv_rt::entry] 8 | fn main() -> ! { 9 | let p = pac::Peripherals::take().unwrap(); 10 | 11 | let mut sysctl = p.SYSCTL.constrain(); 12 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 13 | let gpio = p.GPIO.split(&mut sysctl.apb0); 14 | let gpiohs = p.GPIOHS.split(); 15 | 16 | // Configure clocks (TODO) 17 | let clocks = k210_hal::clock::Clocks::new(); 18 | 19 | // prepare pins 20 | let _uarths_tx = fpioa.io5.into_function(fpioa::UARTHS_TX); 21 | fpioa.io16.into_function(fpioa::GPIOHS0); 22 | let boot_button = gpiohs.gpiohs0.into_pull_up_input(); 23 | 24 | // Configure UART 25 | let serial = p.UARTHS.configure( 26 | 115_200.bps(), 27 | &clocks 28 | ); 29 | let (mut tx, _) = serial.split(); 30 | 31 | // todo: new stdout design (simple Write impl?) 32 | let mut stdout = Stdout(&mut tx); 33 | 34 | writeln!(stdout, "Hello, Rust!").ok(); 35 | 36 | loop { 37 | let input_state = boot_button.try_is_high().unwrap(); 38 | let dir = unsafe { &*pac::GPIO::ptr() }.direction.read().bits(); 39 | writeln!(stdout, "Io16 input: {}; direction value: 0x{:08X}", input_state, dir); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /gdb_init: -------------------------------------------------------------------------------- 1 | target remote :3333 2 | load 3 | c 4 | -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | INCLUDE memory-k210.x 2 | 3 | REGION_ALIAS("REGION_TEXT", SRAM); 4 | REGION_ALIAS("REGION_RODATA", SRAM); 5 | REGION_ALIAS("REGION_DATA", SRAM); 6 | REGION_ALIAS("REGION_BSS", SRAM); 7 | REGION_ALIAS("REGION_HEAP", SRAM); 8 | REGION_ALIAS("REGION_STACK", SRAM); 9 | -------------------------------------------------------------------------------- /openocd.cfg: -------------------------------------------------------------------------------- 1 | transport select jtag 2 | adapter_khz 1000 3 | 4 | set _CHIPNAME riscv 5 | jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x04e4796b 6 | 7 | set _TARGETNAME $_CHIPNAME.cpu 8 | target create $_TARGETNAME riscv -chain-position $_TARGETNAME 9 | 10 | init 11 | halt 12 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | #![no_std] 3 | #![no_main] 4 | 5 | use panic_halt as _; 6 | use k210_hal::prelude::*; 7 | use k210_hal::fpioa; 8 | use k210_hal::pac as pac; 9 | use k210_hal::stdout::Stdout; 10 | 11 | #[riscv_rt::entry] 12 | fn main() -> ! { 13 | let p = pac::Peripherals::take().unwrap(); 14 | let mut sysctl = p.SYSCTL.constrain(); 15 | // Prepare pins for UARTHS 16 | let fpioa = p.FPIOA.split(&mut sysctl.apb0); 17 | let _io5 = fpioa.io5.into_function(fpioa::UARTHS_TX); 18 | 19 | // Configure clocks (TODO) 20 | let clocks = k210_hal::clock::Clocks::new(); 21 | 22 | // Configure UART 23 | let serial = p.UARTHS.configure( 24 | 115_200.bps(), 25 | &clocks 26 | ); 27 | let (mut tx, _) = serial.split(); 28 | 29 | // todo: new stdout design (simple Write impl?) 30 | let mut stdout = Stdout(&mut tx); 31 | 32 | writeln!(stdout, "Hello, Rust!").unwrap(); 33 | 34 | loop { 35 | writeln!(stdout, "Rust NB!").unwrap(); 36 | } 37 | } 38 | --------------------------------------------------------------------------------