From d18a07587d84c56f07fd7efb1787b485ab33c9c7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 26 Jul 2022 15:57:37 +0200 Subject: [PATCH 01/12] Basic working timer, demo with 25% duty cycle LED blink. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/lib.rs | 3 ++ src/main.rs | 22 ++++++++- src/timer.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/timer.rs diff --git a/Cargo.lock b/Cargo.lock index 605e76a..ac7ca06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ ] [[package]] -name = "d1rgb" +name = "d1-playground" version = "0.1.0" dependencies = [ "d1-pac", diff --git a/Cargo.toml b/Cargo.toml index 4e7cfe6..b4d2684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "d1rgb" +name = "d1-playground" version = "0.1.0" edition = "2021" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d5397be --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +#![no_std] + +pub mod timer; diff --git a/src/main.rs b/src/main.rs index 8a80b30..00aa480 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ use panic_halt as _; mod de; +use d1_playground::timer::{Timers, Timer, TimerSource, TimerPrescaler, TimerMode}; + struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; impl core::fmt::Write for Uart { @@ -68,16 +70,32 @@ fn main() -> ! { uart0.halt.write(|w| w.halt_tx().disabled()); unsafe { PRINTER = Some(Uart(uart0)) }; + // Set up timers + let Timers { mut timer0, mut timer1, .. } = Timers::new(p.TIMER); + + timer0.set_source(TimerSource::OSC24_M); + timer1.set_source(TimerSource::OSC24_M); + + timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s + timer1.set_prescaler(TimerPrescaler::P32); // 24M / 32: 0.75M ticks/s + + timer0.set_mode(TimerMode::SINGLE_COUNTING); + timer1.set_mode(TimerMode::SINGLE_COUNTING); + // Blink LED loop { unsafe { println!("Hello, world!"); + // Start both counters for 3M ticks: that's 1s for timer 0 + // and 4s for timer 1. + timer0.start_counter(3_000_000); + timer1.start_counter(3_000_000); gpio.pc_dat.write(|w| w.bits(2)); - riscv::asm::delay(100_000_000); + while timer0.current_value() != 0 { } gpio.pc_dat.write(|w| w.bits(0)); - riscv::asm::delay(100_000_000); + while timer1.current_value() != 0 { } }} } diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..b628a23 --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,137 @@ +use d1_pac::TIMER; +pub use d1_pac::timer::tmr_ctrl::{ + TMR_CLK_SRC_A as TimerSource, + TMR_CLK_PRES_A as TimerPrescaler, + TMR_MODE_A as TimerMode, +}; + +pub struct Timers { + pub timer0: Timer0, + pub timer1: Timer1, +} + +mod sealed { + use d1_pac::{generic::Reg, timer::{tmr_ctrl::TMR_CTRL_SPEC, tmr_intv_value::TMR_INTV_VALUE_SPEC, tmr_cur_value::TMR_CUR_VALUE_SPEC}}; + + use super::*; + + pub trait TimerSealed { + fn ctrl(&self) -> &Reg; + fn interval(&self) -> &Reg; + fn value(&self) -> &Reg; + } + + impl TimerSealed for Timer0 { + #[inline(always)] + fn ctrl(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr0_ctrl + } + + #[inline(always)] + fn interval(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr0_intv_value + } + + #[inline(always)] + fn value(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr0_cur_value + } + } + + impl TimerSealed for Timer1 { + #[inline(always)] + fn ctrl(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr1_ctrl + } + + #[inline(always)] + fn interval(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr1_intv_value + } + + #[inline(always)] + fn value(&self) -> &Reg { + let timer = unsafe { &*TIMER::PTR }; + &timer.tmr1_cur_value + } + } + + impl Timer for Timer0 { } + impl Timer for Timer1 { } +} + +pub struct Timer0 { + _x: (), +} + +pub struct Timer1 { + _x: (), +} + +pub trait Timer: sealed::TimerSealed { + #[inline] + fn set_source(&mut self, variant: TimerSource) { + self.ctrl().modify(|_r, w| { + w.tmr_clk_src().variant(variant); + w + }); + } + + #[inline] + fn set_prescaler(&mut self, variant: TimerPrescaler) { + self.ctrl().modify(|_r, w| { + w.tmr_clk_pres().variant(variant); + w + }); + } + + #[inline] + fn set_mode(&mut self, variant: TimerMode) { + self.ctrl().modify(|_r, w| { + w.tmr_mode().variant(variant); + w + }); + } + + #[inline] + fn start_counter(&mut self, interval: u32) { + self.interval().write(|w| unsafe { + w.bits(interval); + w + }); + // Set the reload AND enable bits at the same time + // TODO: Reset status flag or interrupt flag? + self.ctrl().modify(|_r, w| { + w.tmr_reload().set_bit(); + w.tmr_en().set_bit(); + w + }); + } + + #[inline] + fn current_value(&self) -> u32 { + self.value().read().bits() + } +} + +impl Timers { + pub fn new( + _periph: TIMER, + ) -> Self { + // 1. Configure the timer parameters clock source, prescale factor, and timing mode by writing **TMRn_CTRL_REG**. There is no sequence requirement of configuring the parameters. + // 2. Write the interval value. + // * Write TMRn_INTV_VALUE_REG to configure the interval value for the timer. + // * Write bit[1] of TMRn_CTRL_REG to load the interval value to the timer. The value of the bit will be cleared automatically after loading the interval value. + // 3. Write bit[0] of TMRn_CTRL_REG to start the timer. To get the current value of the timer, read + // TMRn_CUR_VALUE_REG. + Self { + timer0: Timer0 { _x: () }, + timer1: Timer1 { _x: () }, + } + } +} From d3410b3d633e5baf58374d2a838368cdf3f05a2f Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 26 Jul 2022 16:36:03 +0200 Subject: [PATCH 02/12] Basic interrupt functionality (no actual interrupts yet) --- src/main.rs | 37 ++++++++++++++++++++++------- src/timer.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 00aa480..b9c42ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use panic_halt as _; mod de; use d1_playground::timer::{Timers, Timer, TimerSource, TimerPrescaler, TimerMode}; +use riscv::asm::delay; struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; @@ -82,20 +83,40 @@ fn main() -> ! { timer0.set_mode(TimerMode::SINGLE_COUNTING); timer1.set_mode(TimerMode::SINGLE_COUNTING); + let _ = timer0.get_and_clear_interrupt(); + let _ = timer1.get_and_clear_interrupt(); + + // yolo + timer0.set_interrupt_en(true); + // Blink LED - loop { unsafe { - println!("Hello, world!"); + loop { + println!("-------------------------"); + if timer0.get_and_clear_interrupt() { + println!("[PRE]: T0 INT SET"); + } else { + println!("[PRE]: T0 INT CLR"); + } + + if timer1.get_and_clear_interrupt() { + println!("[PRE]: T1 INT SET"); + } else { + println!("[PRE]: T1 INT CLR"); + } + println!("-------------------------"); // Start both counters for 3M ticks: that's 1s for timer 0 - // and 4s for timer 1. + // and 4s for timer 1, for a 25% duty cycle timer0.start_counter(3_000_000); timer1.start_counter(3_000_000); - gpio.pc_dat.write(|w| w.bits(2)); + gpio.pc_dat.write(|w| unsafe { w.bits(2) }); - while timer0.current_value() != 0 { } + while !timer0.get_and_clear_interrupt() { } + println!("T0 DONE"); - gpio.pc_dat.write(|w| w.bits(0)); + gpio.pc_dat.write(|w| unsafe { w.bits(0) }); - while timer1.current_value() != 0 { } - }} + while !timer1.get_and_clear_interrupt() { } + println!("T1 DONE"); + } } diff --git a/src/timer.rs b/src/timer.rs index b628a23..e6abd50 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -19,6 +19,8 @@ mod sealed { fn ctrl(&self) -> &Reg; fn interval(&self) -> &Reg; fn value(&self) -> &Reg; + fn set_interrupt_en(&self, enabled: bool); + fn get_and_clear_interrupt(&self) -> bool; } impl TimerSealed for Timer0 { @@ -39,6 +41,29 @@ mod sealed { let timer = unsafe { &*TIMER::PTR }; &timer.tmr0_cur_value } + + #[inline(always)] + fn get_and_clear_interrupt(&self) -> bool { + let timer = unsafe { &*TIMER::PTR }; + let mut active = false; + timer.tmr_irq_sta.modify(|r, w| { + if r.tmr0_irq_pend().bit_is_set() { + w.tmr0_irq_pend().set_bit(); + active = true; + } + w + }); + active + } + + #[inline(always)] + fn set_interrupt_en(&self, enabled: bool) { + let timer = unsafe { &*TIMER::PTR }; + timer.tmr_irq_en.modify(|_r, w| { + w.tmr0_irq_en().bit(enabled); + w + }); + } } impl TimerSealed for Timer1 { @@ -59,6 +84,29 @@ mod sealed { let timer = unsafe { &*TIMER::PTR }; &timer.tmr1_cur_value } + + #[inline(always)] + fn get_and_clear_interrupt(&self) -> bool { + let timer = unsafe { &*TIMER::PTR }; + let mut active = false; + timer.tmr_irq_sta.modify(|r, w| { + if r.tmr1_irq_pend().bit_is_set() { + w.tmr1_irq_pend().set_bit(); + active = true; + } + w + }); + active + } + + #[inline(always)] + fn set_interrupt_en(&self, enabled: bool) { + let timer = unsafe { &*TIMER::PTR }; + timer.tmr_irq_en.modify(|_r, w| { + w.tmr1_irq_en().bit(enabled); + w + }); + } } impl Timer for Timer0 { } @@ -117,11 +165,21 @@ pub trait Timer: sealed::TimerSealed { fn current_value(&self) -> u32 { self.value().read().bits() } + + #[inline] + fn get_and_clear_interrupt(&self) -> bool { + sealed::TimerSealed::get_and_clear_interrupt(self) + } + + #[inline] + fn set_interrupt_en(&self, enabled: bool) { + sealed::TimerSealed::set_interrupt_en(self, enabled) + } } impl Timers { pub fn new( - _periph: TIMER, + periph: TIMER, ) -> Self { // 1. Configure the timer parameters clock source, prescale factor, and timing mode by writing **TMRn_CTRL_REG**. There is no sequence requirement of configuring the parameters. // 2. Write the interval value. @@ -129,6 +187,12 @@ impl Timers { // * Write bit[1] of TMRn_CTRL_REG to load the interval value to the timer. The value of the bit will be cleared automatically after loading the interval value. // 3. Write bit[0] of TMRn_CTRL_REG to start the timer. To get the current value of the timer, read // TMRn_CUR_VALUE_REG. + periph.tmr_irq_en.write(|w| { + w.tmr0_irq_en().clear_bit(); + w.tmr1_irq_en().clear_bit(); + w + }); + Self { timer0: Timer0 { _x: () }, timer1: Timer1 { _x: () }, From 6b7506ee21d924afa9dc13ffccdd6529ecba40a3 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 26 Jul 2022 17:18:44 +0200 Subject: [PATCH 03/12] Start trying to add an interrupt handler for the timer, no luck yet --- src/main.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index b9c42ec..4219c80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -88,6 +88,17 @@ fn main() -> ! { // yolo timer0.set_interrupt_en(true); + let plic = &p.PLIC; + let clint = &p.CLINT; + plic.prio[75].write(|w| { + w.priority().p1() + }); + plic.mie[2].write(|w| unsafe { + w.bits(1 << 11) + }); + unsafe { riscv::interrupt::enable(); } + let active = (plic.ip[2].read().bits() & (1 << 11)) != 0; + assert!(!active); // Blink LED loop { @@ -111,8 +122,15 @@ fn main() -> ! { timer1.start_counter(3_000_000); gpio.pc_dat.write(|w| unsafe { w.bits(2) }); - while !timer0.get_and_clear_interrupt() { } - println!("T0 DONE"); + loop { + let active = (plic.ip[2].read().bits() & (1 << 11)) != 0; + if active { + println!("T0 DONE"); + break + } + } + // while !timer0.get_and_clear_interrupt() { } + // println!("T0 DONE"); gpio.pc_dat.write(|w| unsafe { w.bits(0) }); @@ -120,3 +138,9 @@ fn main() -> ! { println!("T1 DONE"); } } + +#[export_name = "MachineExternal"] +fn im_an_interrupt() { + println!("I'M AN INTERRUPT"); + panic!() +} From 83f999d14f907701e54e379f91695a016bb47f0b Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 26 Jul 2022 18:25:09 +0200 Subject: [PATCH 04/12] Basic working interrupt setup --- build.rs | 3 +- src/de.rs | 52 ++++++++++++++----------- src/main.rs | 107 ++++++++++++++++++++++++++++----------------------- src/timer.rs | 22 ++++++----- 4 files changed, 101 insertions(+), 83 deletions(-) diff --git a/build.rs b/build.rs index d7d8356..e469908 100644 --- a/build.rs +++ b/build.rs @@ -6,8 +6,7 @@ use std::path::Path; fn main() { let out_dir = env::var("OUT_DIR").expect("No out dir"); let dest_path = Path::new(&out_dir); - let mut f = File::create(&dest_path.join("memory.x")) - .expect("Could not create file"); + let mut f = File::create(&dest_path.join("memory.x")).expect("Could not create file"); f.write_all(include_bytes!("memory.x")) .expect("Could not write file"); diff --git a/src/de.rs b/src/de.rs index a450a0e..c5bfe85 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,26 +1,26 @@ #![allow(dead_code)] -const DE_BASE: u32 = 0x0500_0000; -const DE_SCLK_GATE: u32 = DE_BASE + 0x000; -const DE_HCLK_GATE: u32 = DE_BASE + 0x004; -const DE_AHB_RESET: u32 = DE_BASE + 0x008; -const DE_SCLK_DIV: u32 = DE_BASE + 0x00C; +const DE_BASE: u32 = 0x0500_0000; +const DE_SCLK_GATE: u32 = DE_BASE + 0x000; +const DE_HCLK_GATE: u32 = DE_BASE + 0x004; +const DE_AHB_RESET: u32 = DE_BASE + 0x008; +const DE_SCLK_DIV: u32 = DE_BASE + 0x00C; -const DE_MIXER0: u32 = DE_BASE + 0x0010_0000; -const DE_M0_GLB: u32 = DE_MIXER0 + 0x0_0000; -const DE_M0_BLD: u32 = DE_MIXER0 + 0x0_1000; -const DE_M0_OVL_V: u32 = DE_MIXER0 + 0x0_2000; -const DE_M0_OVL_UI1: u32 = DE_MIXER0 + 0x0_3000; +const DE_MIXER0: u32 = DE_BASE + 0x0010_0000; +const DE_M0_GLB: u32 = DE_MIXER0 + 0x0_0000; +const DE_M0_BLD: u32 = DE_MIXER0 + 0x0_1000; +const DE_M0_OVL_V: u32 = DE_MIXER0 + 0x0_2000; +const DE_M0_OVL_UI1: u32 = DE_MIXER0 + 0x0_3000; const DE_M0_VIDEO_SCALAR: u32 = DE_MIXER0 + 0x2_0000; const DE_M0_UI_SCALAR1: u32 = DE_MIXER0 + 0x4_0000; const DE_M0_POST_PROC1: u32 = DE_MIXER0 + 0xA_0000; const DE_M0_POST_PROC2: u32 = DE_MIXER0 + 0xB_0000; -const DE_M0_DMA: u32 = DE_MIXER0 + 0xC_0000; +const DE_M0_DMA: u32 = DE_MIXER0 + 0xC_0000; -const DE_M0_GLB_CTL: u32 = DE_M0_GLB + 0x000; -const DE_M0_GLB_STS: u32 = DE_M0_GLB + 0x004; +const DE_M0_GLB_CTL: u32 = DE_M0_GLB + 0x000; +const DE_M0_GLB_STS: u32 = DE_M0_GLB + 0x004; const DE_M0_GLB_DBUFFER: u32 = DE_M0_GLB + 0x008; -const DE_M0_GLB_SIZE: u32 = DE_M0_GLB + 0x00C; +const DE_M0_GLB_SIZE: u32 = DE_M0_GLB + 0x00C; const DE_M0_OVL_V_ATTCTL: u32 = DE_M0_OVL_V + 0x000; const DE_M0_OVL_V_MBSIZE: u32 = DE_M0_OVL_V + 0x004; const DE_M0_OVL_V_COOR: u32 = DE_M0_OVL_V + 0x008; @@ -84,11 +84,12 @@ pub unsafe fn init(fb: &[u8]) { write_volatile(DE_AHB_RESET as *mut u32, 0xF); // Hopefully default div is OK. - write_volatile(DE_SCLK_DIV as *mut u32, - (0 << 12) // ROT_SCLK_DIV + write_volatile( + DE_SCLK_DIV as *mut u32, + (0 << 12) // ROT_SCLK_DIV | (0 << 8) // RT_WB_SCLK_DIV | (0 << 4) // CORE1_SCLK_DIV - | (0 << 0) // CORE0_SCLK_DIV + | (0 << 0), // CORE0_SCLK_DIV ); // Hopefully DE2TCON_MUX either doesn't exist or default is fine. @@ -102,14 +103,16 @@ pub unsafe fn init(fb: &[u8]) { // Set OVL_UI1_L0 to alpha=FF, top-addr-only, no-premult, BGR888, no fill, global alpha, enable // NB not sure why BGR is required, since data is in RGB...?? - write_volatile(DE_M0_UI1_ATTCTL_L0 as *mut u32, - (0xFF << 24) | (0 << 23) | (0 << 16) | (0x09 << 8) | (0 << 4) | (1 << 1) | (1 << 0)); + write_volatile( + DE_M0_UI1_ATTCTL_L0 as *mut u32, + (0xFF << 24) | (0 << 23) | (0 << 16) | (0x09 << 8) | (0 << 4) | (1 << 1) | (1 << 0), + ); // Set OVL_UI1_L0 to height=272 width=480 write_volatile(DE_M0_UI1_MBSIZE_L0 as *mut u32, (271 << 16) | (479 << 0)); // Set OVL_UI1_L0 coordinate to 0, 0 write_volatile(DE_M0_UI1_COOR_L0 as *mut u32, (0 << 16) | (0 << 0)); // Set OVL_UI1_L0 pitch to 480*3 bytes/line. - write_volatile(DE_M0_UI1_PITCH_L0 as *mut u32, 480*3); + write_volatile(DE_M0_UI1_PITCH_L0 as *mut u32, 480 * 3); // Set memory start address write_volatile(DE_M0_UI1_TOP_LADD_L0 as *mut u32, fb.as_ptr() as u32); write_volatile(DE_M0_UI1_TOP_HADD as *mut u32, 0); @@ -117,13 +120,16 @@ pub unsafe fn init(fb: &[u8]) { write_volatile(DE_M0_UI1_SIZE as *mut u32, (271 << 16) | (479 << 0)); // Enable Pipe0, no fill - write_volatile(DE_M0_BLD_FILL_COLOR_CTL as *mut u32, 1<<8); + write_volatile(DE_M0_BLD_FILL_COLOR_CTL as *mut u32, 1 << 8); // Pipe0 Input size 272x480 - write_volatile(DE_M0_BLD_CH_ISIZE_P0 as *mut u32, (271<<16) | (479 << 0)); + write_volatile(DE_M0_BLD_CH_ISIZE_P0 as *mut u32, (271 << 16) | (479 << 0)); // Pipe 0 offset apparently needs to be 271,479? Not sure why. write_volatile(DE_M0_BLD_CH_OFFSET_P0 as *mut u32, (271 << 16) | (479 << 0)); // Pipe 0 select from channel 1, pipe 1 from 0, pipe 2 from 2, pipe 3 from 3 - write_volatile(DE_M0_BLD_CH_RTCTL as *mut u32, (3<<12) | (2<<8) | (0<<4) | (1<<0)); + write_volatile( + DE_M0_BLD_CH_RTCTL as *mut u32, + (3 << 12) | (2 << 8) | (0 << 4) | (1 << 0), + ); // Output size 272x480 write_volatile(DE_M0_BLD_SIZE as *mut u32, (271 << 16) | (479 << 0)); } diff --git a/src/main.rs b/src/main.rs index 4219c80..317f150 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ #![no_std] #![no_main] +use d1_pac::{PLIC, TIMER}; use panic_halt as _; mod de; -use d1_playground::timer::{Timers, Timer, TimerSource, TimerPrescaler, TimerMode}; -use riscv::asm::delay; +use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; @@ -45,18 +45,19 @@ fn main() -> ! { // Enable UART0 clock. let ccu = &p.CCU; - ccu.uart_bgr.write(|w| w.uart0_gating().pass().uart0_rst().deassert()); + ccu.uart_bgr + .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); // Set PC1 LED to output. let gpio = &p.GPIO; - gpio.pc_cfg0.write(|w| { - w.pc1_select().output() - .pc0_select().ledc_do() - }); + gpio.pc_cfg0 + .write(|w| w.pc1_select().output().pc0_select().ledc_do()); // Set PB8 and PB9 to function 6, UART0, internal pullup. - gpio.pb_cfg1.write(|w| w.pb8_select().uart0_tx().pb9_select().uart0_rx()); - gpio.pb_pull0.write(|w| w.pc8_pull().pull_up().pc9_pull().pull_up()); + gpio.pb_cfg1 + .write(|w| w.pb8_select().uart0_tx().pb9_select().uart0_rx()); + gpio.pb_pull0 + .write(|w| w.pc8_pull().pull_up().pc9_pull().pull_up()); // Configure UART0 for 115200 8n1. // By default APB1 is 24MHz, use divisor 13 for 115200. @@ -65,19 +66,23 @@ fn main() -> ! { uart0.fcr().write(|w| w.fifoe().set_bit()); uart0.halt.write(|w| w.halt_tx().enabled()); uart0.lcr.write(|w| w.dlab().divisor_latch()); - uart0.dll().write(|w| unsafe { w.dll().bits(13)}); + uart0.dll().write(|w| unsafe { w.dll().bits(13) }); uart0.dlh().write(|w| unsafe { w.dlh().bits(0) }); uart0.lcr.write(|w| w.dlab().rx_buffer().dls().eight()); uart0.halt.write(|w| w.halt_tx().disabled()); unsafe { PRINTER = Some(Uart(uart0)) }; // Set up timers - let Timers { mut timer0, mut timer1, .. } = Timers::new(p.TIMER); + let Timers { + mut timer0, + mut timer1, + .. + } = Timers::new(p.TIMER); timer0.set_source(TimerSource::OSC24_M); timer1.set_source(TimerSource::OSC24_M); - timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s + timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s timer1.set_prescaler(TimerPrescaler::P32); // 24M / 32: 0.75M ticks/s timer0.set_mode(TimerMode::SINGLE_COUNTING); @@ -86,61 +91,67 @@ fn main() -> ! { let _ = timer0.get_and_clear_interrupt(); let _ = timer1.get_and_clear_interrupt(); + unsafe { + riscv::interrupt::enable(); + riscv::register::mie::set_mext(); + } + // yolo timer0.set_interrupt_en(true); + timer1.set_interrupt_en(true); let plic = &p.PLIC; - let clint = &p.CLINT; - plic.prio[75].write(|w| { - w.priority().p1() - }); - plic.mie[2].write(|w| unsafe { - w.bits(1 << 11) - }); - unsafe { riscv::interrupt::enable(); } - let active = (plic.ip[2].read().bits() & (1 << 11)) != 0; - assert!(!active); + + plic.prio[75].write(|w| w.priority().p1()); + plic.prio[76].write(|w| w.priority().p1()); + plic.mie[2].write(|w| unsafe { w.bits((1 << 11) | (1 << 12)) }); // Blink LED loop { - println!("-------------------------"); - if timer0.get_and_clear_interrupt() { - println!("[PRE]: T0 INT SET"); - } else { - println!("[PRE]: T0 INT CLR"); - } - - if timer1.get_and_clear_interrupt() { - println!("[PRE]: T1 INT SET"); - } else { - println!("[PRE]: T1 INT CLR"); - } - println!("-------------------------"); - // Start both counters for 3M ticks: that's 1s for timer 0 // and 4s for timer 1, for a 25% duty cycle timer0.start_counter(3_000_000); timer1.start_counter(3_000_000); gpio.pc_dat.write(|w| unsafe { w.bits(2) }); - loop { - let active = (plic.ip[2].read().bits() & (1 << 11)) != 0; - if active { - println!("T0 DONE"); - break - } - } + unsafe { riscv::asm::wfi() }; // while !timer0.get_and_clear_interrupt() { } - // println!("T0 DONE"); + println!("T0 DONE"); gpio.pc_dat.write(|w| unsafe { w.bits(0) }); - - while !timer1.get_and_clear_interrupt() { } + unsafe { riscv::asm::wfi() }; println!("T1 DONE"); } } #[export_name = "MachineExternal"] fn im_an_interrupt() { - println!("I'M AN INTERRUPT"); - panic!() + let plic = unsafe { &*PLIC::PTR }; + let timer = unsafe { &*TIMER::PTR }; + + let claim = plic.mclaim.read().mclaim(); + println!("claim: {}", claim.bits()); + + match claim.bits() { + 75 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr0_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr0_irq_pend().bit_is_set() {} + } + 76 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr1_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr1_irq_pend().bit_is_set() {} + } + x => { + println!("Unexpected claim: {}", x); + panic!(); + } + } + + // Release claim + plic.mclaim.write(|w| w.mclaim().variant(claim.bits())); } diff --git a/src/timer.rs b/src/timer.rs index e6abd50..5ec3b4f 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,9 +1,7 @@ -use d1_pac::TIMER; pub use d1_pac::timer::tmr_ctrl::{ - TMR_CLK_SRC_A as TimerSource, - TMR_CLK_PRES_A as TimerPrescaler, - TMR_MODE_A as TimerMode, + TMR_CLK_PRES_A as TimerPrescaler, TMR_CLK_SRC_A as TimerSource, TMR_MODE_A as TimerMode, }; +use d1_pac::TIMER; pub struct Timers { pub timer0: Timer0, @@ -11,7 +9,13 @@ pub struct Timers { } mod sealed { - use d1_pac::{generic::Reg, timer::{tmr_ctrl::TMR_CTRL_SPEC, tmr_intv_value::TMR_INTV_VALUE_SPEC, tmr_cur_value::TMR_CUR_VALUE_SPEC}}; + use d1_pac::{ + generic::Reg, + timer::{ + tmr_ctrl::TMR_CTRL_SPEC, tmr_cur_value::TMR_CUR_VALUE_SPEC, + tmr_intv_value::TMR_INTV_VALUE_SPEC, + }, + }; use super::*; @@ -109,8 +113,8 @@ mod sealed { } } - impl Timer for Timer0 { } - impl Timer for Timer1 { } + impl Timer for Timer0 {} + impl Timer for Timer1 {} } pub struct Timer0 { @@ -178,9 +182,7 @@ pub trait Timer: sealed::TimerSealed { } impl Timers { - pub fn new( - periph: TIMER, - ) -> Self { + pub fn new(periph: TIMER) -> Self { // 1. Configure the timer parameters clock source, prescale factor, and timing mode by writing **TMRn_CTRL_REG**. There is no sequence requirement of configuring the parameters. // 2. Write the interval value. // * Write TMRn_INTV_VALUE_REG to configure the interval value for the timer. From 77bf077df21e66729bcb41ba034c99a7f49d4965 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 26 Jul 2022 23:30:59 +0200 Subject: [PATCH 05/12] Basic UART-TX DMA PoC Stops sending DMA after some amount of time. Likely needs more robust error handling, but that's a tomorrow problem. --- .gitignore | 1 + src/binx/timers.rs | 154 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 131 +++++++++++++++++++++++++++++++++----- 4 files changed, 271 insertions(+), 16 deletions(-) create mode 100644 src/binx/timers.rs diff --git a/.gitignore b/.gitignore index a0e7a17..b5feab3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target *.bin +*.txt diff --git a/src/binx/timers.rs b/src/binx/timers.rs new file mode 100644 index 0000000..2115b0e --- /dev/null +++ b/src/binx/timers.rs @@ -0,0 +1,154 @@ +#![no_std] +#![no_main] + +use d1_pac::{PLIC, TIMER}; +use panic_halt as _; +use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; + +struct Uart(d1_pac::UART0); +static mut PRINTER: Option = None; +impl core::fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for byte in s.as_bytes() { + self.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); + while self.0.usr.read().tfnf().bit_is_clear() {} + } + Ok(()) + } +} +pub fn _print(args: core::fmt::Arguments) { + use core::fmt::Write; + unsafe { + PRINTER.as_mut().unwrap().write_fmt(args).ok(); + } +} +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => { + $crate::_print(core::format_args!($($arg)*)); + } +} +#[macro_export] +macro_rules! println { + ($($arg:tt)*) => { + $crate::_print(core::format_args!($($arg)*)); + $crate::print!("\r\n"); + } +} + +#[riscv_rt::entry] +fn main() -> ! { + let p = d1_pac::Peripherals::take().unwrap(); + + // Enable UART0 clock. + let ccu = &p.CCU; + ccu.uart_bgr + .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); + + // Set PC1 LED to output. + let gpio = &p.GPIO; + gpio.pc_cfg0 + .write(|w| w.pc1_select().output().pc0_select().ledc_do()); + + // Set PB8 and PB9 to function 6, UART0, internal pullup. + gpio.pb_cfg1 + .write(|w| w.pb8_select().uart0_tx().pb9_select().uart0_rx()); + gpio.pb_pull0 + .write(|w| w.pc8_pull().pull_up().pc9_pull().pull_up()); + + // Configure UART0 for 115200 8n1. + // By default APB1 is 24MHz, use divisor 13 for 115200. + let uart0 = p.UART0; + uart0.mcr.write(|w| unsafe { w.bits(0) }); + uart0.fcr().write(|w| w.fifoe().set_bit()); + uart0.halt.write(|w| w.halt_tx().enabled()); + uart0.lcr.write(|w| w.dlab().divisor_latch()); + uart0.dll().write(|w| unsafe { w.dll().bits(13) }); + uart0.dlh().write(|w| unsafe { w.dlh().bits(0) }); + uart0.lcr.write(|w| w.dlab().rx_buffer().dls().eight()); + uart0.halt.write(|w| w.halt_tx().disabled()); + unsafe { PRINTER = Some(Uart(uart0)) }; + + // Set up timers + let Timers { + mut timer0, + mut timer1, + .. + } = Timers::new(p.TIMER); + + timer0.set_source(TimerSource::OSC24_M); + timer1.set_source(TimerSource::OSC24_M); + + timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s + timer1.set_prescaler(TimerPrescaler::P32); // 24M / 32: 0.75M ticks/s + + timer0.set_mode(TimerMode::SINGLE_COUNTING); + timer1.set_mode(TimerMode::SINGLE_COUNTING); + + let _ = timer0.get_and_clear_interrupt(); + let _ = timer1.get_and_clear_interrupt(); + + unsafe { + riscv::interrupt::enable(); + riscv::register::mie::set_mext(); + } + + // yolo + timer0.set_interrupt_en(true); + timer1.set_interrupt_en(true); + let plic = &p.PLIC; + + plic.prio[75].write(|w| w.priority().p1()); + plic.prio[76].write(|w| w.priority().p1()); + plic.mie[2].write(|w| unsafe { w.bits((1 << 11) | (1 << 12)) }); + + // Blink LED + loop { + // Start both counters for 3M ticks: that's 1s for timer 0 + // and 4s for timer 1, for a 25% duty cycle + timer0.start_counter(3_000_000); + timer1.start_counter(3_000_000); + gpio.pc_dat.write(|w| unsafe { w.bits(2) }); + + unsafe { riscv::asm::wfi() }; + // while !timer0.get_and_clear_interrupt() { } + println!("T0 DONE"); + + gpio.pc_dat.write(|w| unsafe { w.bits(0) }); + unsafe { riscv::asm::wfi() }; + println!("T1 DONE"); + } +} + +#[export_name = "MachineExternal"] +fn im_an_interrupt() { + let plic = unsafe { &*PLIC::PTR }; + let timer = unsafe { &*TIMER::PTR }; + + let claim = plic.mclaim.read().mclaim(); + println!("INTERRUPT! claim: {}", claim.bits()); + + match claim.bits() { + 75 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr0_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr0_irq_pend().bit_is_set() {} + } + 76 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr1_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr1_irq_pend().bit_is_set() {} + } + x => { + println!("Unexpected claim: {}", x); + panic!(); + } + } + + // Release claim + plic.mclaim.write(|w| w.mclaim().variant(claim.bits())); +} diff --git a/src/lib.rs b/src/lib.rs index d5397be..078d0b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ #![no_std] pub mod timer; +pub mod de; diff --git a/src/main.rs b/src/main.rs index 317f150..270f943 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,15 @@ #![no_std] #![no_main] -use d1_pac::{PLIC, TIMER}; -use panic_halt as _; +use core::sync::atomic::{compiler_fence, Ordering}; -mod de; +use d1_pac::{PLIC, TIMER, UART0}; +use panic_halt as _; use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; +static HOUND: &[u8] = include_bytes!("../hound.txt"); + struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; impl core::fmt::Write for Uart { @@ -48,6 +50,10 @@ fn main() -> ! { ccu.uart_bgr .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); + // DMAC enable + let dmac = &p.DMAC; + ccu.dma_bgr.write(|w| w.gating().pass().rst().deassert()); + // Set PC1 LED to output. let gpio = &p.GPIO; gpio.pc_cfg0 @@ -62,13 +68,35 @@ fn main() -> ! { // Configure UART0 for 115200 8n1. // By default APB1 is 24MHz, use divisor 13 for 115200. let uart0 = p.UART0; + + // UART Mode + // No Auto Flow Control + // No Loop Back + // No RTS_N + // No DTR_N uart0.mcr.write(|w| unsafe { w.bits(0) }); + + // RCVR INT Trigger: 1 char in FIFO + // TXMT INT Trigger: FIFO Empty + // DMA Mode 0 - (???) + // FIFOs Enabled uart0.fcr().write(|w| w.fifoe().set_bit()); + + // TX Halted + // Also has some DMA relevant things? Not set currently uart0.halt.write(|w| w.halt_tx().enabled()); + + // Enable control of baudrates uart0.lcr.write(|w| w.dlab().divisor_latch()); + + // Baudrates uart0.dll().write(|w| unsafe { w.dll().bits(13) }); uart0.dlh().write(|w| unsafe { w.dlh().bits(0) }); + + // Unlatch baud rate, set width uart0.lcr.write(|w| w.dlab().rx_buffer().dls().eight()); + + // Re-enable sending uart0.halt.write(|w| w.halt_tx().disabled()); unsafe { PRINTER = Some(Uart(uart0)) }; @@ -105,22 +133,53 @@ fn main() -> ! { plic.prio[76].write(|w| w.priority().p1()); plic.mie[2].write(|w| unsafe { w.bits((1 << 11) | (1 << 12)) }); - // Blink LED - loop { - // Start both counters for 3M ticks: that's 1s for timer 0 - // and 4s for timer 1, for a 25% duty cycle - timer0.start_counter(3_000_000); - timer1.start_counter(3_000_000); - gpio.pc_dat.write(|w| unsafe { w.bits(2) }); + let mut descriptor = Descriptor { + configuration: 0, + source_address: 0, + destination_address: 0, + byte_counter: 0, + parameter: 0, + link: 0 + }; + let desc_addr: *mut u8 = &mut descriptor as *mut Descriptor as *mut u8; + let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as usize as u64; - unsafe { riscv::asm::wfi() }; - // while !timer0.get_and_clear_interrupt() { } - println!("T0 DONE"); - gpio.pc_dat.write(|w| unsafe { w.bits(0) }); + for chunk in HOUND.chunks(256) { + + descriptor.set_source(chunk.as_ptr() as usize as u64); + descriptor.set_dest(thr_addr); + descriptor.byte_counter = chunk.len() as u32; + + // I think? DMAC_CFG_REGN + descriptor.configuration = 0; + descriptor.configuration |= (0b0 << 30); // BMODE_SEL: Normal + descriptor.configuration |= (0b00 << 25); // DEST_WIDTH: 8-bit + descriptor.configuration |= (0b1 << 24); // DMA_ADDR_MODE: Dest IO Mode + descriptor.configuration |= (0b00 << 22); // Dest block size: 1 + descriptor.configuration |= (0b001110 << 16); // !!! Dest DRQ Type - UART0 + descriptor.configuration |= (0b00 << 9); // Source width 8 bit + descriptor.configuration |= (0b0 << 8); // Source Linear Mode + descriptor.configuration |= (0b00 << 6); // Source block size 1 + descriptor.configuration |= (0b000001 << 0); // Source DRQ type - DRAM + + compiler_fence(Ordering::SeqCst); ////// + + dmac.dmac_desc_addr_reg0.write(|w| { + w.dma_desc_addr().variant((desc_addr as usize >> 2) as u32); + w.dma_desc_high_addr().variant(((desc_addr as usize >> 32) as u8) & 0b11); + w + }); + dmac.dmac_en_reg0.write(|w| w.dma_en().enabled()); + + compiler_fence(Ordering::SeqCst); ////// + + timer0.start_counter(3_000_000); unsafe { riscv::asm::wfi() }; - println!("T1 DONE"); + println!("T0 DONE"); + dmac.dmac_en_reg0.write(|w| w.dma_en().disabled()); } + panic!(); } #[export_name = "MachineExternal"] @@ -129,7 +188,7 @@ fn im_an_interrupt() { let timer = unsafe { &*TIMER::PTR }; let claim = plic.mclaim.read().mclaim(); - println!("claim: {}", claim.bits()); + println!("INTERRUPT! claim: {}", claim.bits()); match claim.bits() { 75 => { @@ -155,3 +214,43 @@ fn im_an_interrupt() { // Release claim plic.mclaim.write(|w| w.mclaim().variant(claim.bits())); } + +#[repr(C, align(4))] +// This gets written to DMAC_DESC_ADDR_REGN in a funky way +pub struct Descriptor { + configuration: u32, + source_address: u32, + destination_address: u32, + byte_counter: u32, + parameter: u32, + link: u32, +} + +impl Descriptor { + fn set_source(&mut self, source: u64) { + assert!(source < (1 << 34)); + self.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_11_00_11111111_11111111; + self.parameter |= (((source >> 32) & 0b11) << 16) as u32; + } + + fn set_dest(&mut self, dest: u64) { + assert!(dest < (1 << 34)); + self.destination_address = dest as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_00_11_11111111_11111111; + self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; + } + + fn end_link(&mut self) { + self.link = 0xFFFF_F800; + } +} + +// Main config register: +// DMAC_CFG_REGN +// Mode: +// DMAC_MODE_REGN From 7f417b17ba3fefb3afbcfb9818fe8fe151ed9fdf Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 27 Jul 2022 01:50:57 +0200 Subject: [PATCH 06/12] Better line based implementation, fix descriptor --- src/main.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 270f943..d843957 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use panic_halt as _; use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; -static HOUND: &[u8] = include_bytes!("../hound.txt"); +static HOUND: &str = include_str!("../hound.txt"); struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; @@ -145,7 +145,7 @@ fn main() -> ! { let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as usize as u64; - for chunk in HOUND.chunks(256) { + for chunk in HOUND.lines() { descriptor.set_source(chunk.as_ptr() as usize as u64); descriptor.set_dest(thr_addr); @@ -153,15 +153,17 @@ fn main() -> ! { // I think? DMAC_CFG_REGN descriptor.configuration = 0; - descriptor.configuration |= (0b0 << 30); // BMODE_SEL: Normal - descriptor.configuration |= (0b00 << 25); // DEST_WIDTH: 8-bit - descriptor.configuration |= (0b1 << 24); // DMA_ADDR_MODE: Dest IO Mode - descriptor.configuration |= (0b00 << 22); // Dest block size: 1 - descriptor.configuration |= (0b001110 << 16); // !!! Dest DRQ Type - UART0 - descriptor.configuration |= (0b00 << 9); // Source width 8 bit - descriptor.configuration |= (0b0 << 8); // Source Linear Mode - descriptor.configuration |= (0b00 << 6); // Source block size 1 - descriptor.configuration |= (0b000001 << 0); // Source DRQ type - DRAM + descriptor.configuration |= 0b0 << 30; // BMODE_SEL: Normal + descriptor.configuration |= 0b00 << 25; // DEST_WIDTH: 8-bit + descriptor.configuration |= 0b1 << 24; // DMA_ADDR_MODE: Dest IO Mode + descriptor.configuration |= 0b00 << 22; // Dest block size: 1 + descriptor.configuration |= 0b001110 << 16; // !!! Dest DRQ Type - UART0 + descriptor.configuration |= 0b00 << 9; // Source width 8 bit + descriptor.configuration |= 0b0 << 8; // Source Linear Mode + descriptor.configuration |= 0b00 << 6; // Source block size 1 + descriptor.configuration |= 0b000001 << 0; // Source DRQ type - DRAM + + descriptor.end_link(); compiler_fence(Ordering::SeqCst); ////// @@ -174,9 +176,10 @@ fn main() -> ! { compiler_fence(Ordering::SeqCst); ////// - timer0.start_counter(3_000_000); + timer0.start_counter(1_500_000); unsafe { riscv::asm::wfi() }; - println!("T0 DONE"); + + println!(""); dmac.dmac_en_reg0.write(|w| w.dma_en().disabled()); } panic!(); @@ -188,7 +191,7 @@ fn im_an_interrupt() { let timer = unsafe { &*TIMER::PTR }; let claim = plic.mclaim.read().mclaim(); - println!("INTERRUPT! claim: {}", claim.bits()); + // println!("INTERRUPT! claim: {}", claim.bits()); match claim.bits() { 75 => { From 843d1c3f6b5e9ea2d89710825a9f23fc95cf726e Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 27 Jul 2022 20:34:28 +0200 Subject: [PATCH 07/12] Start cleaning up DMAC driver --- .gitignore | 1 + src/dmac.rs | 160 +++++++++++++++++++++++++++++++ src/{binx => examples}/timers.rs | 0 src/lib.rs | 1 + 4 files changed, 162 insertions(+) create mode 100644 src/dmac.rs rename src/{binx => examples}/timers.rs (100%) diff --git a/.gitignore b/.gitignore index b5feab3..3e6a154 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target *.bin *.txt +**/*.orig diff --git a/src/dmac.rs b/src/dmac.rs new file mode 100644 index 0000000..63e3908 --- /dev/null +++ b/src/dmac.rs @@ -0,0 +1,160 @@ +#[repr(C, align(4))] +// This gets written to DMAC_DESC_ADDR_REGN in a funky way +pub struct Descriptor { + configuration: u32, + source_address: u32, + destination_address: u32, + byte_counter: u32, + parameter: u32, + link: u32, +} + +impl Descriptor { + pub fn set_source(&mut self, source: u64) { + assert!(source < (1 << 34)); + self.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_11_00_11111111_11111111; + self.parameter |= (((source >> 32) & 0b11) << 16) as u32; + } + + pub fn set_dest(&mut self, dest: u64) { + assert!(dest < (1 << 34)); + self.destination_address = dest as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_00_11_11111111_11111111; + self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; + } + + pub fn end_link(&mut self) { + self.link = 0xFFFF_F800; + } +} + +pub struct DescriptorConfig { + pub source: *const (), + pub destination: *mut (), + + // NOTE: Max is < 2^25, or < 32MiB + pub byte_counter: usize, + pub link: Option<*const ()>, + pub wait_clock_cycles: u8, + + pub bmode: BModeSel, + + pub dest_width: DataWidth, + pub dest_addr_mode: AddressMode, + pub dest_block_size: BlockSize, + pub dest_drq_type: DestDrqType, + + pub src_data_width: DataWidth, + pub src_addr_mode: AddressMode, + pub src_block_size: BlockSize, + pub src_drq_type: SrcDrqType, +} + +#[repr(u8)] +pub enum SrcDrqType { + Sram = 0, + Dram = 1, + OwaRx = 2, + I2sPcm0Rx = 3, + I2sPcm1Rx = 4, + I2sPcm2Rx = 5, + AudioCodec = 7, + Dmic = 8, + GpADC = 12, + TpADC = 13, + Uart0Rx = 14, + Uart1Rx = 15, + Uart2Rx = 16, + Uart3Rx = 17, + Uart4Rx = 18, + Uart5Rx = 19, + Spi0Rx = 22, + Spi1Rx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +#[repr(u8)] +pub enum DestDrqType { + Sram = 0, + Dram = 1, + OwaTx = 2, + I2sPcm0Tx = 3, + I2sPcm1Tx = 4, + I2sPcm2Tx = 5, + AudioCodec = 7, + IrTx = 13, + Uart0Tx = 14, + Uart1Tx = 15, + Uart2Tx = 16, + Uart3Tx = 17, + Uart4Tx = 18, + Uart5Tx = 19, + Spi0Tx = 22, + Spi1Tx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Ledc = 42, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +// TODO: Verify bits or bytes? +pub enum BlockSize { + Byte1, + Byte4, + Byte8, + Byte16 +} + +pub enum AddressMode { + LinearMode, + IoMode, +} + +pub enum DataWidth { + Bit8, + Bit16, + Bit32, + Bit64, +} + +pub enum BModeSel { + Normal, + BMode, +} + +// descriptor.set_source(chunk.as_ptr() as usize as u64); +// descriptor.set_dest(thr_addr); +// descriptor.byte_counter = chunk.len() as u32; + +// // I think? DMAC_CFG_REGN +// descriptor.configuration = 0; +// descriptor.configuration |= 0b0 << 30; // BMODE_SEL: Normal +// descriptor.configuration |= 0b00 << 25; // DEST_WIDTH: 8-bit +// descriptor.configuration |= 0b1 << 24; // DMA_ADDR_MODE: Dest IO Mode +// descriptor.configuration |= 0b00 << 22; // Dest block size: 1 +// descriptor.configuration |= 0b001110 << 16; // !!! Dest DRQ Type - UART0 +// descriptor.configuration |= 0b00 << 9; // Source width 8 bit +// descriptor.configuration |= 0b0 << 8; // Source Linear Mode +// descriptor.configuration |= 0b00 << 6; // Source block size 1 +// descriptor.configuration |= 0b000001 << 0; // Source DRQ type - DRAM + +// descriptor.end_link(); diff --git a/src/binx/timers.rs b/src/examples/timers.rs similarity index 100% rename from src/binx/timers.rs rename to src/examples/timers.rs diff --git a/src/lib.rs b/src/lib.rs index 6130256..d4409f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod plic; pub mod timer; pub mod de; +pub mod dmac; From c3f6267dc5f22c877b8065136b051f8034053363 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 27 Jul 2022 22:22:03 +0200 Subject: [PATCH 08/12] Update layout --- src/dmac.rs | 160 ---------------------- src/dmac/descriptor.rs | 298 +++++++++++++++++++++++++++++++++++++++++ src/dmac/mod.rs | 2 + src/main.rs | 34 ----- 4 files changed, 300 insertions(+), 194 deletions(-) delete mode 100644 src/dmac.rs create mode 100644 src/dmac/descriptor.rs create mode 100644 src/dmac/mod.rs diff --git a/src/dmac.rs b/src/dmac.rs deleted file mode 100644 index 63e3908..0000000 --- a/src/dmac.rs +++ /dev/null @@ -1,160 +0,0 @@ -#[repr(C, align(4))] -// This gets written to DMAC_DESC_ADDR_REGN in a funky way -pub struct Descriptor { - configuration: u32, - source_address: u32, - destination_address: u32, - byte_counter: u32, - parameter: u32, - link: u32, -} - -impl Descriptor { - pub fn set_source(&mut self, source: u64) { - assert!(source < (1 << 34)); - self.source_address = source as u32; - // 332222222222 11 11 11111100 00000000 - // 109876543210 98 76 54321098 76543210 - self.parameter &= 0b111111111111_11_00_11111111_11111111; - self.parameter |= (((source >> 32) & 0b11) << 16) as u32; - } - - pub fn set_dest(&mut self, dest: u64) { - assert!(dest < (1 << 34)); - self.destination_address = dest as u32; - // 332222222222 11 11 11111100 00000000 - // 109876543210 98 76 54321098 76543210 - self.parameter &= 0b111111111111_00_11_11111111_11111111; - self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; - } - - pub fn end_link(&mut self) { - self.link = 0xFFFF_F800; - } -} - -pub struct DescriptorConfig { - pub source: *const (), - pub destination: *mut (), - - // NOTE: Max is < 2^25, or < 32MiB - pub byte_counter: usize, - pub link: Option<*const ()>, - pub wait_clock_cycles: u8, - - pub bmode: BModeSel, - - pub dest_width: DataWidth, - pub dest_addr_mode: AddressMode, - pub dest_block_size: BlockSize, - pub dest_drq_type: DestDrqType, - - pub src_data_width: DataWidth, - pub src_addr_mode: AddressMode, - pub src_block_size: BlockSize, - pub src_drq_type: SrcDrqType, -} - -#[repr(u8)] -pub enum SrcDrqType { - Sram = 0, - Dram = 1, - OwaRx = 2, - I2sPcm0Rx = 3, - I2sPcm1Rx = 4, - I2sPcm2Rx = 5, - AudioCodec = 7, - Dmic = 8, - GpADC = 12, - TpADC = 13, - Uart0Rx = 14, - Uart1Rx = 15, - Uart2Rx = 16, - Uart3Rx = 17, - Uart4Rx = 18, - Uart5Rx = 19, - Spi0Rx = 22, - Spi1Rx = 23, - Usb0Ep1 = 30, - Usb0Ep2 = 31, - Usb0Ep3 = 32, - Usb0Ep4 = 33, - Usb0Ep5 = 34, - Twi0 = 43, - Twi1 = 44, - Twi2 = 45, - Twi3 = 46, -} - -#[repr(u8)] -pub enum DestDrqType { - Sram = 0, - Dram = 1, - OwaTx = 2, - I2sPcm0Tx = 3, - I2sPcm1Tx = 4, - I2sPcm2Tx = 5, - AudioCodec = 7, - IrTx = 13, - Uart0Tx = 14, - Uart1Tx = 15, - Uart2Tx = 16, - Uart3Tx = 17, - Uart4Tx = 18, - Uart5Tx = 19, - Spi0Tx = 22, - Spi1Tx = 23, - Usb0Ep1 = 30, - Usb0Ep2 = 31, - Usb0Ep3 = 32, - Usb0Ep4 = 33, - Usb0Ep5 = 34, - Ledc = 42, - Twi0 = 43, - Twi1 = 44, - Twi2 = 45, - Twi3 = 46, -} - -// TODO: Verify bits or bytes? -pub enum BlockSize { - Byte1, - Byte4, - Byte8, - Byte16 -} - -pub enum AddressMode { - LinearMode, - IoMode, -} - -pub enum DataWidth { - Bit8, - Bit16, - Bit32, - Bit64, -} - -pub enum BModeSel { - Normal, - BMode, -} - -// descriptor.set_source(chunk.as_ptr() as usize as u64); -// descriptor.set_dest(thr_addr); -// descriptor.byte_counter = chunk.len() as u32; - -// // I think? DMAC_CFG_REGN -// descriptor.configuration = 0; -// descriptor.configuration |= 0b0 << 30; // BMODE_SEL: Normal -// descriptor.configuration |= 0b00 << 25; // DEST_WIDTH: 8-bit -// descriptor.configuration |= 0b1 << 24; // DMA_ADDR_MODE: Dest IO Mode -// descriptor.configuration |= 0b00 << 22; // Dest block size: 1 -// descriptor.configuration |= 0b001110 << 16; // !!! Dest DRQ Type - UART0 -// descriptor.configuration |= 0b00 << 9; // Source width 8 bit -// descriptor.configuration |= 0b0 << 8; // Source Linear Mode -// descriptor.configuration |= 0b00 << 6; // Source block size 1 -// descriptor.configuration |= 0b000001 << 0; // Source DRQ type - DRAM - -// descriptor.end_link(); diff --git a/src/dmac/descriptor.rs b/src/dmac/descriptor.rs new file mode 100644 index 0000000..5f71b6f --- /dev/null +++ b/src/dmac/descriptor.rs @@ -0,0 +1,298 @@ +#[repr(C, align(4))] +pub struct Descriptor { + configuration: u32, + source_address: u32, + destination_address: u32, + byte_counter: u32, + parameter: u32, + link: u32, +} + +// TODO: THIS COULD PROBABLY BE A BITFIELD LIBRARY +pub struct DescriptorConfig { + pub source: *const (), + pub destination: *mut (), + + // NOTE: Max is < 2^25, or < 32MiB + pub byte_counter: usize, + pub link: Option<*const ()>, + pub wait_clock_cycles: u8, + + pub bmode: BModeSel, + + pub dest_width: DataWidth, + pub dest_addr_mode: AddressMode, + pub dest_block_size: BlockSize, + pub dest_drq_type: DestDrqType, + + pub src_data_width: DataWidth, + pub src_addr_mode: AddressMode, + pub src_block_size: BlockSize, + pub src_drq_type: SrcDrqType, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum SrcDrqType { + Sram = 0, + Dram = 1, + OwaRx = 2, + I2sPcm0Rx = 3, + I2sPcm1Rx = 4, + I2sPcm2Rx = 5, + AudioCodec = 7, + Dmic = 8, + GpADC = 12, + TpADC = 13, + Uart0Rx = 14, + Uart1Rx = 15, + Uart2Rx = 16, + Uart3Rx = 17, + Uart4Rx = 18, + Uart5Rx = 19, + Spi0Rx = 22, + Spi1Rx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum DestDrqType { + Sram = 0, + Dram = 1, + OwaTx = 2, + I2sPcm0Tx = 3, + I2sPcm1Tx = 4, + I2sPcm2Tx = 5, + AudioCodec = 7, + IrTx = 13, + Uart0Tx = 14, + Uart1Tx = 15, + Uart2Tx = 16, + Uart3Tx = 17, + Uart4Tx = 18, + Uart5Tx = 19, + Spi0Tx = 22, + Spi1Tx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Ledc = 42, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +// TODO: Verify bits or bytes? +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum BlockSize { + Byte1 = 0b00, + Byte4 = 0b01, + Byte8 = 0b10, + Byte16 = 0b11, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum AddressMode { + LinearMode = 0, + IoMode = 1, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum DataWidth { + Bit8 = 0b00, + Bit16 = 0b01, + Bit32 = 0b10, + Bit64 = 0b11, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum BModeSel { + Normal, + BMode, +} + +// Descriptor + +impl Descriptor { + pub fn set_source(&mut self, source: u64) { + assert!(source < (1 << 34)); + self.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_11_00_11111111_11111111; + self.parameter |= (((source >> 32) & 0b11) << 16) as u32; + } + + pub fn set_dest(&mut self, dest: u64) { + assert!(dest < (1 << 34)); + self.destination_address = dest as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_00_11_11111111_11111111; + self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; + } + + pub fn end_link(&mut self) { + self.link = 0xFFFF_F800; + } +} + +impl TryFrom for Descriptor { + type Error = (); + + fn try_from(value: DescriptorConfig) -> Result { + let source = value.source as usize; + let destination = value.destination as usize; + + if source as usize >= (1 << 34) { + return Err(()); + } + if destination as usize >= (1 << 34) { + return Err(()); + } + if value.byte_counter >= (1 << 25) { + return Err(()); + } + if let Some(link) = value.link { + let link = link as usize; + if (link & 0b11) != 0 { + return Err(()); + } + } + + let mut descriptor = Descriptor { + configuration: 0, + source_address: 0, + destination_address: 0, + byte_counter: 0, + parameter: 0, + link: 0, + }; + + // Set source + descriptor.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + descriptor.parameter &= 0b111111111111_11_00_11111111_11111111; + descriptor.parameter |= (((source >> 32) & 0b11) << 16) as u32; + + // Set dest + descriptor.destination_address = destination as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + descriptor.parameter &= 0b111111111111_00_11_11111111_11111111; + descriptor.parameter |= (((destination >> 32) & 0b11) << 18) as u32; + + descriptor.byte_counter = value.byte_counter as u32; + + // Set configuration + descriptor.configuration |= value.bmode.to_desc_bits(); + descriptor.configuration |= value.dest_width.to_desc_bits_dest(); + descriptor.configuration |= value.dest_addr_mode.to_desc_bits_dest(); + descriptor.configuration |= value.dest_block_size.to_desc_bits_dest(); + descriptor.configuration |= value.dest_drq_type.to_desc_bits(); + descriptor.configuration |= value.src_data_width.to_desc_bits_src(); + descriptor.configuration |= value.src_addr_mode.to_desc_bits_src(); + descriptor.configuration |= value.src_block_size.to_desc_bits_src(); + descriptor.configuration |= value.src_drq_type.to_desc_bits(); + + if let Some(link) = value.link { + descriptor.link = link as u32; + // We already verified above the low bits of `value.link` are clear, + // no need to re-mask the current state of `descriptor.link`. + descriptor.link |= ((link as usize >> 32) as u32) & 0b11 + } else { + descriptor.end_link(); + } + + Ok(descriptor) + } +} + +// DescriptorConfig + +// SrcDrqType + +impl SrcDrqType { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + // 6 bits, no shift + ((*self as u8) & 0b11_1111) as u32 + } +} + +// DestDrqType + +impl DestDrqType { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + (((*self as u8) & 0b11_1111) as u32) << 16 + } +} + +// BlockSize + +impl BlockSize { + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 22 + } + + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 6 + } +} + +// AddressMode + +impl AddressMode { + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 8 + } + + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 24 + } +} + +// DataWidth + +impl DataWidth { + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 25 + } + + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 9 + } +} + +// BModeSel + +impl BModeSel { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 30 + } +} diff --git a/src/dmac/mod.rs b/src/dmac/mod.rs new file mode 100644 index 0000000..b70930b --- /dev/null +++ b/src/dmac/mod.rs @@ -0,0 +1,2 @@ +pub mod descriptor; + diff --git a/src/main.rs b/src/main.rs index 2c76ec8..7dcf11a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -221,40 +221,6 @@ fn im_an_interrupt() { plic.complete(claim); } -#[repr(C, align(4))] -// This gets written to DMAC_DESC_ADDR_REGN in a funky way -pub struct Descriptor { - configuration: u32, - source_address: u32, - destination_address: u32, - byte_counter: u32, - parameter: u32, - link: u32, -} - -impl Descriptor { - fn set_source(&mut self, source: u64) { - assert!(source < (1 << 34)); - self.source_address = source as u32; - // 332222222222 11 11 11111100 00000000 - // 109876543210 98 76 54321098 76543210 - self.parameter &= 0b111111111111_11_00_11111111_11111111; - self.parameter |= (((source >> 32) & 0b11) << 16) as u32; - } - - fn set_dest(&mut self, dest: u64) { - assert!(dest < (1 << 34)); - self.destination_address = dest as u32; - // 332222222222 11 11 11111100 00000000 - // 109876543210 98 76 54321098 76543210 - self.parameter &= 0b111111111111_00_11_11111111_11111111; - self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; - } - - fn end_link(&mut self) { - self.link = 0xFFFF_F800; - } -} // Main config register: // DMAC_CFG_REGN From 8d5de01043a5b8929f705f2391891fa623ab8009 Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 27 Jul 2022 23:24:27 +0200 Subject: [PATCH 09/12] Move demo code over --- src/dmac/mod.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- src/main.rs | 77 ++++++++++++++----------------- 3 files changed, 154 insertions(+), 46 deletions(-) diff --git a/src/dmac/mod.rs b/src/dmac/mod.rs index b70930b..62b65a9 100644 --- a/src/dmac/mod.rs +++ b/src/dmac/mod.rs @@ -1,2 +1,121 @@ +use core::{ + ptr::NonNull, + sync::atomic::{fence, Ordering}, +}; + +use d1_pac::{ + dmac::{dmac_desc_addr_reg::DMAC_DESC_ADDR_REG_SPEC, dmac_en_reg::DMAC_EN_REG_SPEC}, + generic::Reg, + CCU, DMAC, +}; + +use self::descriptor::Descriptor; + pub mod descriptor; +pub struct Dmac { + pub dmac: DMAC, // TODO: not this + pub channels: [Channel; 16], +} + +impl Dmac { + pub fn new(dmac: DMAC, ccu: &mut CCU) -> Self { + ccu.dma_bgr.write(|w| w.gating().pass().rst().deassert()); + Self { + dmac, + channels: [ + Channel { idx: 0 }, + Channel { idx: 1 }, + Channel { idx: 2 }, + Channel { idx: 3 }, + Channel { idx: 4 }, + Channel { idx: 5 }, + Channel { idx: 6 }, + Channel { idx: 7 }, + Channel { idx: 8 }, + Channel { idx: 9 }, + Channel { idx: 10 }, + Channel { idx: 11 }, + Channel { idx: 12 }, + Channel { idx: 13 }, + Channel { idx: 14 }, + Channel { idx: 15 }, + ], + } + } +} + +pub struct Channel { + idx: u8, +} + +impl Channel { + pub unsafe fn desc_addr_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_desc_addr_reg0, + 1 => &dmac.dmac_desc_addr_reg1, + 2 => &dmac.dmac_desc_addr_reg2, + 3 => &dmac.dmac_desc_addr_reg3, + 4 => &dmac.dmac_desc_addr_reg4, + 5 => &dmac.dmac_desc_addr_reg5, + 6 => &dmac.dmac_desc_addr_reg6, + 7 => &dmac.dmac_desc_addr_reg7, + 8 => &dmac.dmac_desc_addr_reg8, + 9 => &dmac.dmac_desc_addr_reg9, + 10 => &dmac.dmac_desc_addr_reg10, + 11 => &dmac.dmac_desc_addr_reg11, + 12 => &dmac.dmac_desc_addr_reg12, + 13 => &dmac.dmac_desc_addr_reg13, + 14 => &dmac.dmac_desc_addr_reg14, + 15 => &dmac.dmac_desc_addr_reg15, + _ => panic!(), + } + } + + pub unsafe fn en_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_en_reg0, + 1 => &dmac.dmac_en_reg1, + 2 => &dmac.dmac_en_reg2, + 3 => &dmac.dmac_en_reg3, + 4 => &dmac.dmac_en_reg4, + 5 => &dmac.dmac_en_reg5, + 6 => &dmac.dmac_en_reg6, + 7 => &dmac.dmac_en_reg7, + 8 => &dmac.dmac_en_reg8, + 9 => &dmac.dmac_en_reg9, + 10 => &dmac.dmac_en_reg10, + 11 => &dmac.dmac_en_reg11, + 12 => &dmac.dmac_en_reg12, + 13 => &dmac.dmac_en_reg13, + 14 => &dmac.dmac_en_reg14, + 15 => &dmac.dmac_en_reg15, + _ => panic!(), + } + } + + pub unsafe fn start_descriptor(&mut self, desc: NonNull) { + // TODO: Check if channel is idle? + + fence(Ordering::SeqCst); ////// + + let desc_addr = desc.as_ptr() as usize; + self.desc_addr_reg().write(|w| { + w.dma_desc_addr().variant((desc_addr >> 2) as u32); + w.dma_desc_high_addr() + .variant(((desc_addr >> 32) as u8) & 0b11); + w + }); + self.en_reg().write(|w| w.dma_en().enabled()); + + fence(Ordering::SeqCst); ////// + } + + pub unsafe fn stop_dma(&mut self) { + self.en_reg().write(|w| w.dma_en().disabled()); + + fence(Ordering::SeqCst); ////// + } +} diff --git a/src/lib.rs b/src/lib.rs index d4409f3..204ba7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -pub mod plic; -pub mod timer; pub mod de; pub mod dmac; +pub mod plic; +pub mod timer; diff --git a/src/main.rs b/src/main.rs index 7dcf11a..f1415b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,14 @@ #![no_std] #![no_main] +use core::ptr::NonNull; use core::sync::atomic::{compiler_fence, Ordering}; use d1_pac::{Interrupt, TIMER, UART0}; +use d1_playground::dmac::descriptor::{ + AddressMode, BModeSel, BlockSize, DataWidth, DescriptorConfig, DestDrqType, SrcDrqType, +}; +use d1_playground::dmac::Dmac; use panic_halt as _; use d1_playground::plic::{Plic, Priority}; @@ -44,16 +49,15 @@ macro_rules! println { #[riscv_rt::entry] fn main() -> ! { - let p = d1_pac::Peripherals::take().unwrap(); + let mut p = d1_pac::Peripherals::take().unwrap(); // Enable UART0 clock. - let ccu = &p.CCU; + let ccu = &mut p.CCU; ccu.uart_bgr .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); // DMAC enable - let dmac = &p.DMAC; - ccu.dma_bgr.write(|w| w.gating().pass().rst().deassert()); + let mut dmac = Dmac::new(p.DMAC, ccu); // Set PC1 LED to output. let gpio = &p.GPIO; @@ -136,46 +140,29 @@ fn main() -> ! { plic.unmask(Interrupt::TIMER1); } - let mut descriptor = Descriptor { - configuration: 0, - source_address: 0, - destination_address: 0, - byte_counter: 0, - parameter: 0, - link: 0 - }; - let desc_addr: *mut u8 = &mut descriptor as *mut Descriptor as *mut u8; - let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as usize as u64; - + let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as *mut (); for chunk in HOUND.lines() { - - descriptor.set_source(chunk.as_ptr() as usize as u64); - descriptor.set_dest(thr_addr); - descriptor.byte_counter = chunk.len() as u32; - - // I think? DMAC_CFG_REGN - descriptor.configuration = 0; - descriptor.configuration |= 0b0 << 30; // BMODE_SEL: Normal - descriptor.configuration |= 0b00 << 25; // DEST_WIDTH: 8-bit - descriptor.configuration |= 0b1 << 24; // DMA_ADDR_MODE: Dest IO Mode - descriptor.configuration |= 0b00 << 22; // Dest block size: 1 - descriptor.configuration |= 0b001110 << 16; // !!! Dest DRQ Type - UART0 - descriptor.configuration |= 0b00 << 9; // Source width 8 bit - descriptor.configuration |= 0b0 << 8; // Source Linear Mode - descriptor.configuration |= 0b00 << 6; // Source block size 1 - descriptor.configuration |= 0b000001 << 0; // Source DRQ type - DRAM - - descriptor.end_link(); - - compiler_fence(Ordering::SeqCst); ////// - - dmac.dmac_desc_addr_reg0.write(|w| { - w.dma_desc_addr().variant((desc_addr as usize >> 2) as u32); - w.dma_desc_high_addr().variant(((desc_addr as usize >> 32) as u8) & 0b11); - w - }); - dmac.dmac_en_reg0.write(|w| w.dma_en().enabled()); + let d_cfg = DescriptorConfig { + source: chunk.as_ptr().cast(), + destination: thr_addr, + byte_counter: chunk.len(), + link: None, + wait_clock_cycles: 0, + bmode: BModeSel::Normal, + dest_width: DataWidth::Bit8, + dest_addr_mode: AddressMode::IoMode, + dest_block_size: BlockSize::Byte1, + dest_drq_type: DestDrqType::Uart0Tx, + src_data_width: DataWidth::Bit8, + src_addr_mode: AddressMode::LinearMode, + src_block_size: BlockSize::Byte1, + src_drq_type: SrcDrqType::Dram, + }; + let descriptor = d_cfg.try_into().unwrap(); + unsafe { + dmac.channels[0].start_descriptor(NonNull::from(&descriptor)); + } compiler_fence(Ordering::SeqCst); ////// @@ -183,7 +170,10 @@ fn main() -> ! { unsafe { riscv::asm::wfi() }; println!(""); - dmac.dmac_en_reg0.write(|w| w.dma_en().disabled()); + + unsafe { + dmac.channels[0].stop_dma(); + } } panic!(); } @@ -221,7 +211,6 @@ fn im_an_interrupt() { plic.complete(claim); } - // Main config register: // DMAC_CFG_REGN // Mode: From 2cfe933ec59e742e76ec2567d11f93a42c03eb03 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 28 Jul 2022 01:00:56 +0200 Subject: [PATCH 10/12] Handshake example --- src/dmac/descriptor.rs | 1 + src/dmac/mod.rs | 44 ++++++++++++++++++++++++++- src/main.rs | 69 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 7 deletions(-) diff --git a/src/dmac/descriptor.rs b/src/dmac/descriptor.rs index 5f71b6f..a17d69d 100644 --- a/src/dmac/descriptor.rs +++ b/src/dmac/descriptor.rs @@ -1,3 +1,4 @@ +#[derive(Clone)] #[repr(C, align(4))] pub struct Descriptor { configuration: u32, diff --git a/src/dmac/mod.rs b/src/dmac/mod.rs index 62b65a9..8dfa103 100644 --- a/src/dmac/mod.rs +++ b/src/dmac/mod.rs @@ -4,7 +4,7 @@ use core::{ }; use d1_pac::{ - dmac::{dmac_desc_addr_reg::DMAC_DESC_ADDR_REG_SPEC, dmac_en_reg::DMAC_EN_REG_SPEC}, + dmac::{dmac_desc_addr_reg::DMAC_DESC_ADDR_REG_SPEC, dmac_en_reg::DMAC_EN_REG_SPEC, dmac_mode_reg::DMAC_MODE_REG_SPEC}, generic::Reg, CCU, DMAC, }; @@ -96,6 +96,43 @@ impl Channel { } } + pub unsafe fn mode_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_mode_reg0, + 1 => &dmac.dmac_mode_reg1, + 2 => &dmac.dmac_mode_reg2, + 3 => &dmac.dmac_mode_reg3, + 4 => &dmac.dmac_mode_reg4, + 5 => &dmac.dmac_mode_reg5, + 6 => &dmac.dmac_mode_reg6, + 7 => &dmac.dmac_mode_reg7, + 8 => &dmac.dmac_mode_reg8, + 9 => &dmac.dmac_mode_reg9, + 10 => &dmac.dmac_mode_reg10, + 11 => &dmac.dmac_mode_reg11, + 12 => &dmac.dmac_mode_reg12, + 13 => &dmac.dmac_mode_reg13, + 14 => &dmac.dmac_mode_reg14, + 15 => &dmac.dmac_mode_reg15, + _ => panic!(), + } + } + + pub unsafe fn set_channel_modes(&mut self, src: ChannelMode, dst: ChannelMode) { + self.mode_reg().write(|w| { + match src { + ChannelMode::Wait => w.dma_src_mode().waiting(), + ChannelMode::Handshake => w.dma_src_mode().handshake(), + }; + match dst { + ChannelMode::Wait => w.dma_dst_mode().waiting(), + ChannelMode::Handshake => w.dma_dst_mode().handshake(), + }; + w + }) + } + pub unsafe fn start_descriptor(&mut self, desc: NonNull) { // TODO: Check if channel is idle? @@ -119,3 +156,8 @@ impl Channel { fence(Ordering::SeqCst); ////// } } + +pub enum ChannelMode { + Wait, + Handshake, +} diff --git a/src/main.rs b/src/main.rs index f1415b4..0c9493f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,15 @@ #![no_std] #![no_main] +use core::cell::UnsafeCell; use core::ptr::NonNull; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{compiler_fence, Ordering, fence}; use d1_pac::{Interrupt, TIMER, UART0}; use d1_playground::dmac::descriptor::{ - AddressMode, BModeSel, BlockSize, DataWidth, DescriptorConfig, DestDrqType, SrcDrqType, + AddressMode, BModeSel, BlockSize, DataWidth, DescriptorConfig, DestDrqType, SrcDrqType, Descriptor, }; -use d1_playground::dmac::Dmac; +use d1_playground::dmac::{Dmac, ChannelMode}; use panic_halt as _; use d1_playground::plic::{Plic, Priority}; @@ -20,6 +21,7 @@ struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; impl core::fmt::Write for Uart { fn write_str(&mut self, s: &str) -> core::fmt::Result { + while self.0.usr.read().tfnf().bit_is_clear() {} for byte in s.as_bytes() { self.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); while self.0.usr.read().tfnf().bit_is_clear() {} @@ -27,6 +29,14 @@ impl core::fmt::Write for Uart { Ok(()) } } +fn print_raw(data: &[u8]) { + let uart = unsafe { PRINTER.as_mut().unwrap() }; + while uart.0.usr.read().tfnf().bit_is_clear() {} + for byte in data { + uart.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); + while uart.0.usr.read().tfnf().bit_is_clear() {} + } +} pub fn _print(args: core::fmt::Arguments) { use core::fmt::Write; unsafe { @@ -85,7 +95,8 @@ fn main() -> ! { // TXMT INT Trigger: FIFO Empty // DMA Mode 0 - (???) // FIFOs Enabled - uart0.fcr().write(|w| w.fifoe().set_bit()); + uart0.hsk.write(|w| w.hsk().handshake()); + uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1().rt().quarter_full()); // TX Halted // Also has some DMA relevant things? Not set currently @@ -103,6 +114,7 @@ fn main() -> ! { // Re-enable sending uart0.halt.write(|w| w.halt_tx().disabled()); + unsafe { PRINTER = Some(Uart(uart0)) }; // Set up timers @@ -140,9 +152,55 @@ fn main() -> ! { plic.unmask(Interrupt::TIMER1); } + let data_buf = UnsafeCell::new([0u8; 16]); + let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as *mut (); + let rhr_addr = unsafe { &*UART0::PTR }.rbr() as *const _ as *const (); + + let rx_desc_base: Descriptor = DescriptorConfig { + source: rhr_addr, + destination: data_buf.get().cast(), + byte_counter: 16, + link: None, + wait_clock_cycles: 0, + bmode: BModeSel::Normal, + dest_width: DataWidth::Bit8, + dest_addr_mode: AddressMode::LinearMode, + dest_block_size: BlockSize::Byte1, + dest_drq_type: DestDrqType::Dram, + src_data_width: DataWidth::Bit8, + src_addr_mode: AddressMode::IoMode, + src_block_size: BlockSize::Byte1, + src_drq_type: SrcDrqType::Uart0Rx, + }.try_into().unwrap(); + + let mut rx_desc = None; for chunk in HOUND.lines() { + if rx_desc.is_some() { + // TODO: How to tell of DMA channel is done? + if unsafe { dmac.channels[1].en_reg() }.read().dma_en().bit_is_clear() { + println!("USER INPUT: --------------"); + let _ = rx_desc.take(); + print_raw(unsafe { + fence(Ordering::SeqCst); + core::slice::from_raw_parts( + data_buf.get().cast(), + 16, + ) + }); + println!("\r\n--------------------------"); + } + } + + if rx_desc.is_none() { + let desc = rx_desc.insert(rx_desc_base.clone()); + unsafe { + dmac.channels[1].set_channel_modes(ChannelMode::Handshake, ChannelMode::Wait); + dmac.channels[1].start_descriptor(NonNull::from(desc)); + } + } + let d_cfg = DescriptorConfig { source: chunk.as_ptr().cast(), destination: thr_addr, @@ -161,11 +219,10 @@ fn main() -> ! { }; let descriptor = d_cfg.try_into().unwrap(); unsafe { + dmac.channels[0].set_channel_modes(ChannelMode::Wait, ChannelMode::Handshake); dmac.channels[0].start_descriptor(NonNull::from(&descriptor)); } - compiler_fence(Ordering::SeqCst); ////// - timer0.start_counter(1_500_000); unsafe { riscv::asm::wfi() }; From 1a0cb66436b51abce137e2e7d25dd6c3f0fe5715 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 28 Jul 2022 02:02:38 +0200 Subject: [PATCH 11/12] Mess with RX DMA, probably going to use interrupts instead. --- src/dmac/descriptor.rs | 2 +- src/main.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dmac/descriptor.rs b/src/dmac/descriptor.rs index a17d69d..21e7d85 100644 --- a/src/dmac/descriptor.rs +++ b/src/dmac/descriptor.rs @@ -1,4 +1,4 @@ -#[derive(Clone)] +#[derive(Clone, Debug)] #[repr(C, align(4))] pub struct Descriptor { configuration: u32, diff --git a/src/main.rs b/src/main.rs index 0c9493f..1707d9d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,7 +96,8 @@ fn main() -> ! { // DMA Mode 0 - (???) // FIFOs Enabled uart0.hsk.write(|w| w.hsk().handshake()); - uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1().rt().quarter_full()); + uart0.dma_req_en.modify(|_r, w| w.timeout_enable().set_bit()); + uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1()); // TX Halted // Also has some DMA relevant things? Not set currently @@ -152,7 +153,7 @@ fn main() -> ! { plic.unmask(Interrupt::TIMER1); } - let data_buf = UnsafeCell::new([0u8; 16]); + let data_buf = UnsafeCell::new([b'x'; 16]); let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as *mut (); let rhr_addr = unsafe { &*UART0::PTR }.rbr() as *const _ as *const (); @@ -180,16 +181,19 @@ fn main() -> ! { if rx_desc.is_some() { // TODO: How to tell of DMA channel is done? if unsafe { dmac.channels[1].en_reg() }.read().dma_en().bit_is_clear() { + fence(Ordering::SeqCst); println!("USER INPUT: --------------"); - let _ = rx_desc.take(); + println!("{:?}", rx_desc.take()); print_raw(unsafe { - fence(Ordering::SeqCst); core::slice::from_raw_parts( data_buf.get().cast(), 16, ) }); println!("\r\n--------------------------"); + } else { + fence(Ordering::SeqCst); + println!("{:?}", &rx_desc); } } From 88137752b8f36618463f8bd94b402580474049f5 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 28 Jul 2022 02:20:00 +0200 Subject: [PATCH 12/12] Well that was easy --- src/main.rs | 78 ++++++++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1707d9d..61e9bdc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,9 +95,18 @@ fn main() -> ! { // TXMT INT Trigger: FIFO Empty // DMA Mode 0 - (???) // FIFOs Enabled - uart0.hsk.write(|w| w.hsk().handshake()); - uart0.dma_req_en.modify(|_r, w| w.timeout_enable().set_bit()); - uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1()); + // uart0.hsk.write(|w| w.hsk().handshake()); + // uart0.dma_req_en.modify(|_r, w| w.timeout_enable().set_bit()); + // uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1()); + uart0.fcr().write(|w| { + w.fifoe().set_bit(); + w.rt().half_full(); + w + }); + uart0.ier().write(|w| { + w.erbfi().set_bit(); + w + }); // TX Halted // Also has some DMA relevant things? Not set currently @@ -146,65 +155,19 @@ fn main() -> ! { timer0.set_interrupt_en(true); timer1.set_interrupt_en(true); let plic = Plic::new(p.PLIC); + unsafe { + plic.set_priority(Interrupt::UART0, Priority::P1); plic.set_priority(Interrupt::TIMER0, Priority::P1); plic.set_priority(Interrupt::TIMER1, Priority::P1); + plic.unmask(Interrupt::UART0); plic.unmask(Interrupt::TIMER0); plic.unmask(Interrupt::TIMER1); } - let data_buf = UnsafeCell::new([b'x'; 16]); - let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as *mut (); - let rhr_addr = unsafe { &*UART0::PTR }.rbr() as *const _ as *const (); - - let rx_desc_base: Descriptor = DescriptorConfig { - source: rhr_addr, - destination: data_buf.get().cast(), - byte_counter: 16, - link: None, - wait_clock_cycles: 0, - bmode: BModeSel::Normal, - dest_width: DataWidth::Bit8, - dest_addr_mode: AddressMode::LinearMode, - dest_block_size: BlockSize::Byte1, - dest_drq_type: DestDrqType::Dram, - src_data_width: DataWidth::Bit8, - src_addr_mode: AddressMode::IoMode, - src_block_size: BlockSize::Byte1, - src_drq_type: SrcDrqType::Uart0Rx, - }.try_into().unwrap(); - - let mut rx_desc = None; for chunk in HOUND.lines() { - if rx_desc.is_some() { - // TODO: How to tell of DMA channel is done? - if unsafe { dmac.channels[1].en_reg() }.read().dma_en().bit_is_clear() { - fence(Ordering::SeqCst); - println!("USER INPUT: --------------"); - println!("{:?}", rx_desc.take()); - print_raw(unsafe { - core::slice::from_raw_parts( - data_buf.get().cast(), - 16, - ) - }); - println!("\r\n--------------------------"); - } else { - fence(Ordering::SeqCst); - println!("{:?}", &rx_desc); - } - } - - if rx_desc.is_none() { - let desc = rx_desc.insert(rx_desc_base.clone()); - unsafe { - dmac.channels[1].set_channel_modes(ChannelMode::Handshake, ChannelMode::Wait); - dmac.channels[1].start_descriptor(NonNull::from(desc)); - } - } - let d_cfg = DescriptorConfig { source: chunk.as_ptr().cast(), destination: thr_addr, @@ -243,6 +206,7 @@ fn main() -> ! { fn im_an_interrupt() { let plic = unsafe { Plic::summon() }; let timer = unsafe { &*TIMER::PTR }; + let uart0 = unsafe { &*UART0::PTR }; let claim = plic.claim(); // println!("claim: {}", claim.bits()); @@ -262,6 +226,16 @@ fn im_an_interrupt() { // Wait for the interrupt to clear to avoid repeat interrupts while timer.tmr_irq_sta.read().tmr1_irq_pend().bit_is_set() {} } + Interrupt::UART0 => { + println!(""); + println!("UART SAYS: "); + while uart0.usr.read().rfne().bit_is_set() { + let byte = uart0.rbr().read().rbr().bits(); + uart0.thr().write(|w| unsafe { w.thr().bits(byte) }); + while uart0.usr.read().tfnf().bit_is_clear() {} + } + println!(""); + } x => { println!("Unexpected claim: {:?}", x); panic!();