diff options
Diffstat (limited to 'src-riscv')
l--------- | src-riscv/.#main.rs | 1 | ||||
-rw-r--r-- | src-riscv/blink.rs | 70 | ||||
-rw-r--r-- | src-riscv/boot.S | 11 | ||||
-rw-r--r-- | src-riscv/led.rs | 42 | ||||
-rw-r--r-- | src-riscv/log.rs | 36 | ||||
-rwxr-xr-x | src-riscv/main.rs | 215 | ||||
-rwxr-xr-x | src-riscv/usb.rs | 42 |
7 files changed, 417 insertions, 0 deletions
diff --git a/src-riscv/.#main.rs b/src-riscv/.#main.rs new file mode 120000 index 0000000..988fc15 --- /dev/null +++ b/src-riscv/.#main.rs @@ -0,0 +1 @@ +bjc@ditto.691749627316654132
\ No newline at end of file diff --git a/src-riscv/blink.rs b/src-riscv/blink.rs new file mode 100644 index 0000000..967cde6 --- /dev/null +++ b/src-riscv/blink.rs @@ -0,0 +1,70 @@ +use core::convert::Infallible; + +// use gd32vf103xx_hal as hal; +use stm32f30x_hal as hal; + +use hal::{ + //eclic::{self, EclicExt}, + pac::{self, Interrupt}, + prelude::*, + time::Hertz, + timer::{Event, Timer}, +}; +use nb; +use riscv::interrupt; + +use crate::led::LED; + +pub struct Task { + timer: Timer<pac::TIMER6>, + frequency: Hertz, + led: LED, +} + +static mut TIMER_FIRED: bool = false; + +impl Task { + pub fn new(mut timer: Timer<pac::TIMER6>, frequency: Hertz, led: LED) -> Self { + // pac::ECLIC::setup(Interrupt::TIMER6, eclic::TriggerType::RisingEdge, eclic::Level::L0, eclic::Priority::P3); + // unsafe { pac::ECLIC::unmask(Interrupt::TIMER6); } + // assert!(pac::ECLIC::is_enabled(Interrupt::TIMER6)); + timer.listen(Event::Update); + + Self { timer, frequency, led } + } + + pub fn poll(&mut self) -> nb::Result<(), Infallible> { + interrupt::free(|_cs| { + if unsafe { TIMER_FIRED } { + unsafe { TIMER_FIRED = false }; + self.led.toggle(); + self.timer.start(self.frequency); + } + }); + Err(nb::Error::WouldBlock) + } +} + +/* + * because i'm using ‘wfi’ to sleep as much as possible, i need to + * actually schedule the timer to fire an interrupt. that, in turn, + * requires a handler. + * + * why? because, for efficiency reasons, ‘_irq_handler’ uses the + * bumblebee core ‘jalmnxti’ csr, and the default entry in the irq + * vector is ‘0’. so the core jumps to 0, which is the ‘_start’ entry + * point. but it does this *from the interrupt*, which masks the + * interrupt (because it's currently being serviced), so any + * subsequent firings are never triggered, nor any interrupts at lower + * priority. + * + * so it looks like the core resets every other time it's + * started. adding a real isr avoids these problems. + */ +#[export_name="TIMER6"] +fn timer6() { + // logln!("I timer6 I"); + let regs = unsafe { &*pac::TIMER6::ptr() }; + regs.intf.write(|w| w.upif().clear_bit()); + unsafe { TIMER_FIRED = true }; +} diff --git a/src-riscv/boot.S b/src-riscv/boot.S new file mode 100644 index 0000000..d31e5fe --- /dev/null +++ b/src-riscv/boot.S @@ -0,0 +1,11 @@ + .global _start + .section .text.init +_start: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la sp, _stack_top + + csrr a0, mhartid + tail main diff --git a/src-riscv/led.rs b/src-riscv/led.rs new file mode 100644 index 0000000..536121b --- /dev/null +++ b/src-riscv/led.rs @@ -0,0 +1,42 @@ +use gd32vf103xx_hal::{ + gpio::{Floating, Input, Output, PushPull, Pxx, State, gpioa::PA7}, +}; +use embedded_hal::digital::v2::OutputPin; + +pub struct LED { + pin: Pxx<Output<PushPull>>, + state: State, +} + +impl LED { + pub fn new(pin: PA7<Input<Floating>>) -> Self { + let mut p = pin.into_push_pull_output().downgrade(); + p.set_low().ok(); + Self { pin: p, state: State::Low } + } + + pub fn is_on(&self) -> bool { + match self.state { + State::High => true, + State::Low => false, + } + } + + pub fn on(&mut self) { + self.state = State::High; + self.pin.set_high().ok(); + } + + pub fn off(&mut self) { + self.state = State::Low; + self.pin.set_low().ok(); + } + + pub fn toggle(&mut self) { + if self.is_on() { + self.off(); + } else { + self.on(); + } + } +} diff --git a/src-riscv/log.rs b/src-riscv/log.rs new file mode 100644 index 0000000..ddb6792 --- /dev/null +++ b/src-riscv/log.rs @@ -0,0 +1,36 @@ +use core::fmt::{write, Arguments}; + +use gd32vf103xx_hal::{ + serial::Tx, + pac::USART1, +}; +use riscv::interrupt::{self, Mutex}; + +#[macro_export] +macro_rules! log { + ($($args:tt)+) => { + $crate::log::log_args(core::format_args!($($args)+)) + } +} + +#[macro_export] +macro_rules! logln { + () => ({ kprint!("\r\n") }); + ($fmt: literal $(, $($arg: tt)+)?) => { + log!(concat!($fmt, "\n") $(, $($arg)+)?) + } +} + +static mut TX: Mutex<Option<Tx<USART1>>> = Mutex::new(None); + +pub fn init(tx: Tx<USART1>) { + interrupt::free(|_cs| { + unsafe { TX.get_mut().insert(tx) }; + }); +} + +pub fn log_args(args: Arguments) { + interrupt::free(|_cs| { + unsafe { TX.get_mut().as_mut().map(|tx| write(tx, args)) }; + }); +} diff --git a/src-riscv/main.rs b/src-riscv/main.rs new file mode 100755 index 0000000..68fa8da --- /dev/null +++ b/src-riscv/main.rs @@ -0,0 +1,215 @@ +#![no_std] +#![no_main] + +mod blink; +mod led; +mod log; +mod usb; + +// use gd32vf103xx_hal as hal; +use stm32f30x_hal as hal; + +use hal::{ + afio::AfioExt, + eclic::{self, EclicExt}, + gpio::GpioExt, + pac::{self, Peripherals}, + rcu::RcuExt, + serial::Serial, + time::{Hertz, MegaHertz}, + timer::Timer, +}; +use riscv::{ + asm::wfi, + interrupt, +}; +use riscv_rt::entry; +use usb_device::prelude::*; + +use led::LED; +use usb::{USB, UsbBus}; + +static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + +#[entry] +fn main(_hartid: usize) -> ! { + let p = Peripherals::take().expect("couldn't take peripherals"); + + pac::ECLIC::reset(); + pac::ECLIC::set_threshold_level(eclic::Level::L0); + pac::ECLIC::set_level_priority_bits(eclic::LevelPriorityBits::L3P1); + + let mut rcu = p.RCU + .configure() + .ext_hf_clock(MegaHertz(8)) + .sysclk(MegaHertz(96)) + .freeze(); + let mut afio = p.AFIO.constrain(&mut rcu); + let gpioa = p.GPIOA.split(&mut rcu); + + // TODO: figure out how to use the usb serial on the start board. + // + // this version has to be wired up physically. + let serial = Serial::new( + p.USART1, + (gpioa.pa2, gpioa.pa3), + Default::default(), + &mut afio, + &mut rcu, + ); + let (tx, _rx) = serial.split(); + log::init(tx); + logln!("luchie starting"); + + let timer = Timer::<pac::TIMER6>::timer6(p.TIMER6, Hertz(5), &mut rcu); + let led = LED::new(gpioa.pa7); + let mut blink = blink::Task::new(timer, Hertz(5), led); + + let usb = USB { + usb_global: p.USBFS_GLOBAL, + usb_device: p.USBFS_DEVICE, + usb_pwrclk: p.USBFS_PWRCLK, + pin_dm: gpioa.pa11, + pin_dp: gpioa.pa12, + hclk: rcu.clocks.hclk() + }; + logln!("hclk: {:?}", rcu.clocks.hclk().0); + + let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY }); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Fake company") + .product("Enumeration test") + .serial_number("TEST") + .device_class(0) + .build(); + + //let mut serial = SerialPort::new(&bus_alloc); + + unsafe { interrupt::enable() }; + + loop { + let mut can_sleep = true; + + if let Ok(_) = blink.poll() { + can_sleep = false; + } + if usb_dev.poll(&mut []) { + logln!("usb"); + can_sleep = false; + } + + if can_sleep && false { + log!("!"); + unsafe { wfi() }; + } + } +} +#[export_name="ExceptionHandler"] +fn exception_handler(_frame: &riscv_rt::TrapFrame) -> ! { + spin(); +} + +#[export_name="DefaultHandler"] +fn default_handler() -> ! { + spin(); +} + +#[export_name="MachineTimer"] +fn machine_timer() { + spin(); +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + interrupt::free(|_cs| { + log!("!!! panic "); + if let Some(loc) = info.location() { + log!("in {}:{} ", loc.file(), loc.line()); + } + if let Some(msg) = info.payload().downcast_ref::<&str>() { + log!("⇒ {} ", msg); + } + logln!("!!!"); + }); + spin(); +} + +fn spin() -> ! { + loop { unsafe { wfi() } }; +} + +/* +#![no_std] +#![no_main] + +mod usb; + +use riscv::asm::wfi; +use riscv_rt::entry; +use gd32vf103xx_hal::prelude::*; +use gd32vf103xx_hal::pac; + +use usb::{USB, UsbBus}; +use usb_device::prelude::*; +use usbd_serial::SerialPort; + +static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + + // Configure clocks + let mut rcu = dp.RCU.configure() + .ext_hf_clock(8.mhz()) + .sysclk(96.mhz()) + .freeze(); + + assert!(rcu.clocks.usbclk_valid()); + + let gpioa = dp.GPIOA.split(&mut rcu); + let usb = USB { + usb_global: dp.USBFS_GLOBAL, + usb_device: dp.USBFS_DEVICE, + usb_pwrclk: dp.USBFS_PWRCLK, + pin_dm: gpioa.pa11, + pin_dp: gpioa.pa12, + hclk: rcu.clocks.hclk() + }; + + let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY }); + + let mut serial = SerialPort::new(&usb_bus); + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Fake company") + .product("Enumeration test") + .serial_number("TEST") + .device_class(0) + .build(); + + loop { + if usb_dev.poll(&mut [&mut serial]) { + } + } +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { +// interrupt::free(|_cs| { +// log!("!!! panic "); + if let Some(loc) = info.location() { +// log!("in {}:{} ", loc.file(), loc.line()); + } + if let Some(msg) = info.payload().downcast_ref::<&str>() { +// log!("⇒ {} ", msg); + } +// logln!("!!!"); +// }); + spin(); +} + +fn spin() -> ! { + loop { unsafe { wfi() } }; +} +*/ diff --git a/src-riscv/usb.rs b/src-riscv/usb.rs new file mode 100755 index 0000000..1ec36af --- /dev/null +++ b/src-riscv/usb.rs @@ -0,0 +1,42 @@ +use gd32vf103xx_hal::pac; +use gd32vf103xx_hal::gpio::{Input, Floating, gpioa::{PA11, PA12}}; +use gd32vf103xx_hal::time::Hertz; +pub use synopsys_usb_otg::UsbBus; +use synopsys_usb_otg::UsbPeripheral; + +#[allow(dead_code)] +pub struct USB { + pub usb_global: pac::USBFS_GLOBAL, + pub usb_device: pac::USBFS_DEVICE, + pub usb_pwrclk: pac::USBFS_PWRCLK, + pub pin_dm: PA11<Input<Floating>>, + pub pin_dp: PA12<Input<Floating>>, + pub hclk: Hertz, +} + +unsafe impl Sync for USB {} + +unsafe impl UsbPeripheral for USB { + const REGISTERS: *const () = pac::USBFS_GLOBAL::ptr() as *const (); + + const HIGH_SPEED: bool = false; + const FIFO_DEPTH_WORDS: usize = 320; + const ENDPOINT_COUNT: usize = 4; + + fn enable() { + let rcu = unsafe { &*pac::RCU::ptr() }; + + riscv::interrupt::free(|_| { + // Enable USB peripheral + rcu.ahben.modify(|_, w| w.usbfsen().set_bit()); + + // Reset USB peripheral + rcu.ahbrst.modify(|_, w| w.usbfsrst().set_bit()); + rcu.ahbrst.modify(|_, w| w.usbfsrst().clear_bit()); + }); + } + + fn ahb_frequency_hz(&self) -> u32 { + self.hclk.0 + } +} |