From 5e2f0e81bb2bccfb08341a06c06e45fb78fd49ca Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Wed, 23 Jun 2021 14:09:26 +0200 Subject: [PATCH] fixed st-flash (instead of st-util) --- .vscode/launch.json | 2 +- CHANGELOG.md | 38 +++--- Cargo.toml | 7 +- README.md | 6 +- examples/itm_rtic_hello.rs | 4 + examples/pmw3389.rs | 14 +-- examples/rtic_bare1.rs | 2 + examples/rtic_bare7.rs | 14 +-- examples/rtt-pmw3389-sine.rs | 206 ++++++++++++++++++++++++++------- examples/rtt-pwm-sine-task.rs | 15 ++- examples/rtt-pwm-sine.rs | 2 +- examples/rtt-timing.rs | 4 +- examples/rtt_rtic_i2c.rs | 138 +++++++++++++--------- examples/rtt_rtic_usb_mouse.rs | 1 + examples/usb-mouse.rs | 13 ++- openocd.gdb | 2 +- src/main.rs | 20 ---- src/pmw3389.rs | 23 +--- src/pmw3389e.rs | 16 +-- 19 files changed, 341 insertions(+), 186 deletions(-) delete mode 100644 src/main.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index 3fcc60a..b0ce2bf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -150,4 +150,4 @@ "cpu": "cortex-m4", } ] -} \ No newline at end of file +}. \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 39a885d..ec61480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,47 +1,53 @@ # Changelog +## 2021-03-19 + +- `examples/itm_rtic_hello_48MHz.rs`, example to trace ITM, when processor runs at 48MHz, useful to debug USB applications. + +- `.vscode/launch.json`, added 48MHz itm tracing profiles. (Now consistenly using `stlink.cfg`.) + ## 2021-03-18 -- examples/usb-mouse.rs, a very small example using external hid library. +- `examples/usb-mouse.rs`, a very small example using external hid library. ## 2021-03-07 -- examples/rtic_bare7.rs, using embedded HAL. -- examples/rtic_bare8.rs, serial communication, bad design. -- examples/rtic_bare9.rs, serial communication, good design. +- `examples/rtic_bare7.rs`, using embedded HAL. +- `examples/rtic_bare8.rs`, serial communication, bad design. +- `examples/rtic_bare9.rs`, serial communication, good design. ## 2021-03-05 -- examples/rtic_bare6.rs, setup and validate the clock tree. +- `examples/rtic_bare6.rs`, setup and validate the clock tree. ## 2021-02-28 -- examples/rtic_bare2.rs, raw timer access. -- examples/rtic_bare3.rs, timing abstractions. -- examples/rtic_bare4.rs, a simple bare metal peripheral access API. -- examples/rtic_bare5.rs, write your own C-like peripheral access API. +- `examples/rtic_bare2.rs`, raw timer access. +- `examples/rtic_bare3.rs`, timing abstractions. +- `examples/rtic_bare4.rs`, a simple bare metal peripheral access API. +- `examples/rtic_bare5.rs`, write your own C-like peripheral access API. ## 2021-02-26 -- examples/bare1.rs, bare metal 101! +- `examples/bare1.rs`, bare metal 101! ## 2021-02-23 -- examples/rtic_blinky.rs, added instructions to terminal based debugging +- `examples/rtic_blinky.rs`, added instructions to terminal based debugging ## 2021-02-22 -- memory.x, reduced flash size to 128k to match light-weight target -- Cargo.toml, updated dependencies to latest stm32f4xx-hal/pac +- `memory.x`, reduced flash size to 128k to match light-weight target +- `Cargo.toml`, updated dependencies to latest `stm32f4xx-hal/pac` Some experiments (wip): -- examples/rtt_rtic_i2c.rs, spi emulation over i2c -- src/pwm3389e, driver using emulated spi +- `examples/rtt_rtic_i2c.rs`, spi emulation over i2c +- `src/pwm3389e`, driver using emulated spi ## 2021-02-16 -- rtt_rtic_usb_mouse updated +- `rtt_rtic_usb_mouse` updated Notice, requires release build ## 2021-02-15 diff --git a/Cargo.toml b/Cargo.toml index 76ff65f..e4af31a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ version = "0.1.0" [dependencies] cortex-m = { version = "0.7.1", features = ["linker-plugin-lto"] } +# cortex-m = { version = "0.7.1" } cortex-m-rt = "0.6.13" cortex-m-semihosting = "0.3.7" cortex-m-rtic = "0.5.5" @@ -27,9 +28,10 @@ panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] } panic-semihosting = "0.5.6" # Tracing -rtt-target = { version = "0.3.0", features = ["cortex-m"] } +rtt-target = { version = "0.3.1", features = ["cortex-m"] } nb = "1.0.0" usbd-hid = "0.5.0" +micromath = "1.1.0" [dependencies.stm32f4] version = "0.13.0" @@ -37,7 +39,7 @@ features = ["stm32f411", "rt"] [dependencies.stm32f4xx-hal] -version = "0.8.3" +version = "0.9.0" features = ["rt", "stm32f411", "usb_fs"] # Enable to use the latest git version # gitgit = "https://github.com/stm32-rs/stm32f4xx-hal" @@ -56,6 +58,7 @@ codegen-units = 1 overflow-checks = false [profile.release] +incremental = false codegen-units = 1 # better optimizations debug = true # symbols are nice and they don't increase the size on Flash lto = true # better optimizations diff --git a/README.md b/README.md index 88e331d..c1b6a8a 100644 --- a/README.md +++ b/README.md @@ -197,9 +197,9 @@ D+ used for re-enumeration. You don't need to connect the V+ from the USB cable, - If this does not work you can try to erase the flash memory (the program running on the STM32F401/F11). ``` shell - > st-util erase - st-flash 1.6.1 - 2021-01-11T16:02:14 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages. + > st-flash erase + st-flash 1.7.0 + 2021-06-23T14:07:35 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages. Mass erasing....... ``` diff --git a/examples/itm_rtic_hello.rs b/examples/itm_rtic_hello.rs index 963183d..013f4fd 100644 --- a/examples/itm_rtic_hello.rs +++ b/examples/itm_rtic_hello.rs @@ -9,6 +9,10 @@ use stm32f4; const APP: () = { #[init] fn init(cx: init::Context) { + // Set up the system clock. + let rcc = ctx.device.RCC.constrain(); + let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + let mut p = cx.core; let stim = &mut p.ITM.stim[0]; for a in 0..=10 { diff --git a/examples/pmw3389.rs b/examples/pmw3389.rs index 746cf15..20795ac 100644 --- a/examples/pmw3389.rs +++ b/examples/pmw3389.rs @@ -86,15 +86,15 @@ const APP: () = { device.SPI2, (sck, miso, mosi), MODE_3, - stm32f4xx_hal::time::KiloHertz(2000).into(), + stm32f4xx_hal::time::KiloHertz(200).into(), clocks, ); - let mut delay = DwtDelay::new(&mut core.DWT, clocks); + let delay = DwtDelay::new(&mut core.DWT, clocks); let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap(); // set in burst mode - pmw3389.write_register(Register::MotionBurst, 0x00); + pmw3389.write_register(Register::MotionBurst, 0x00).unwrap(); // semantically, the monotonic timer is frozen at time "zero" during `init` // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value @@ -111,8 +111,10 @@ const APP: () = { static mut COUNTER: u32 = 0; static mut POS_X: i64 = 0; + // run each ms *COUNTER += 1; - if *COUNTER == 1000 / RATIO { + if *COUNTER == 1000 { + // run each s cx.spawn.trace(*POS_X).unwrap(); *COUNTER = 0; } @@ -121,9 +123,7 @@ const APP: () = { *POS_X += x as i64; // task should run each second N ms (16_000 cycles at 16MHz) - cx.schedule - .poll(cx.scheduled + (RATIO * 16_000).cycles()) - .unwrap(); + cx.schedule.poll(cx.scheduled + 16_000.cycles()).unwrap(); } #[task(priority = 1)] diff --git a/examples/rtic_bare1.rs b/examples/rtic_bare1.rs index 11248f4..261388d 100644 --- a/examples/rtic_bare1.rs +++ b/examples/rtic_bare1.rs @@ -9,6 +9,7 @@ #![no_main] #![no_std] +use cortex_m_semihosting::hprintln; use panic_semihosting as _; use stm32f4; @@ -18,6 +19,7 @@ const APP: () = { #[inline(never)] // avoid inlining of this function/task #[no_mangle] // to strip hash from symbols (easier to read) fn init(_cx: init::Context) { + hprintln!("hello"); let mut x = core::u32::MAX - 1; loop { // cortex_m::asm::bkpt(); diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs index 0f2dea1..cd3b2c8 100644 --- a/examples/rtic_bare7.rs +++ b/examples/rtic_bare7.rs @@ -17,7 +17,7 @@ use stm32f4xx_hal::{ gpio::{gpioa::PA5, Output, PushPull}, prelude::*, }; -; + use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin}; const OFFSET: u32 = 8_000_000; @@ -144,7 +144,7 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // // Our `PA5<Output<PushPull>>` implements `OutputPin` trait, thus // we can pass the `led` resource to `_toggle_generic`. -// +// // The error type is given by the stm32f4xx-hal implementation: // where `core::convert::Infallible` is used to indicate // there are no errors to be expected (hence infallible). @@ -205,16 +205,16 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // is the same behind drivers for USART communication, USB, PMW3389 etc. // // 5. More details: -// +// // Looking closer at the implementation: // `led: &mut dyn OutputPin<Error = E>` // // You may ask what kind of mumbo jumbo is at play here. // -// This is the way to express that we expect a mutable reference to a trait object +// This is the way to express that we expect a mutable reference to a trait object // that implements the `OutputPin`. Since we will change the underlying object // (in this case an GPIOA pin 5) the reference needs to be mutable. -// +// // Trait objects are further explained in the Rust book. // The `dyn` keyword indicates dynamic dispatch (through a VTABLE). // https://doc.rust-lang.org/std/keyword.dyn.html @@ -237,5 +237,5 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) { // // You might find Rust to have long compile times. Yes you are right, // and this type of deep analysis done in release mode is part of the story. -// On the other hand, the aggressive optimization allows us to code -// in a generic high level fashion and still have excellent performing binaries. \ No newline at end of file +// On the other hand, the aggressive optimization allows us to code +// in a generic high level fashion and still have excellent performing binaries. diff --git a/examples/rtt-pmw3389-sine.rs b/examples/rtt-pmw3389-sine.rs index 0aae89b..b007b37 100644 --- a/examples/rtt-pmw3389-sine.rs +++ b/examples/rtt-pmw3389-sine.rs @@ -6,9 +6,8 @@ #![no_main] #![no_std] -// use core::f32::consts::PI; use cortex_m::{asm, peripheral::DWT}; -// use panic_halt as _; + use panic_rtt_target as _; use rtic::cyccnt::{Instant, U32Ext as _}; use rtt_target::{rprint, rprintln, rtt_init_print}; @@ -16,7 +15,41 @@ use rtt_target::{rprint, rprintln, rtt_init_print}; use core::f32::consts::PI; use micromath::F32Ext; -use stm32f4xx_hal::{bb, gpio::Speed, prelude::*, pwm, stm32}; +use stm32f4xx_hal::{ + bb, + dwt::Dwt, + gpio::Speed, + gpio::{ + gpiob::{PB10, PB4}, + gpioc::{PC2, PC3}, + Alternate, Output, PushPull, + }, + prelude::*, + pwm, + rcc::Clocks, + spi::Spi, + stm32, +}; + +use embedded_hal::spi::MODE_3; +use panic_rtt_target as _; + +use app::{ + pmw3389::{self, Register}, + DwtDelay, +}; + +type PMW3389T = pmw3389::Pmw3389< + Spi< + stm32f4xx_hal::stm32::SPI2, + ( + PB10<Alternate<stm32f4xx_hal::gpio::AF5>>, + PC2<Alternate<stm32f4xx_hal::gpio::AF5>>, + PC3<Alternate<stm32f4xx_hal::gpio::AF5>>, + ), + >, + PB4<Output<PushPull>>, +>; include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs")); @@ -25,28 +58,64 @@ const APP: () = { struct Resources { // late resources TIM1: stm32::TIM1, + pmw3389: PMW3389T, } - #[init(schedule = [pwm_out])] + #[init(schedule = [pwm_out, poll])] fn init(mut cx: init::Context) -> init::LateResources { rtt_init_print!(); rprintln!("init"); - let dp = cx.device; + + let device = cx.device; + let mut core = cx.core; // Initialize (enable) the monotonic timer (CYCCNT) - cx.core.DCB.enable_trace(); - cx.core.DWT.enable_cycle_counter(); - - let rcc = dp.RCC.constrain(); - // Set up the system clock. 48 MHz? - let clocks = rcc - .cfgr - // .use_hse(8.mhz()) - // .sysclk(48.mhz()) - .sysclk(96.mhz()) - .pclk1(24.mhz()) - .freeze(); - - let gpioa = dp.GPIOA.split(); + core.DCB.enable_trace(); + core.DWT.enable_cycle_counter(); + + let rcc = device.RCC.constrain(); + // Set up the system clock. 96 MHz? + let clocks = rcc.cfgr.sysclk(96.mhz()).pclk1(24.mhz()).freeze(); + + // Configure SPI + // spi2 + // sck - pb10, (yellow) + // miso - pc2, (red) + // mosi - pc3, (orange) + // ncs - pb4, (long yellow) + // motion - (brown) + // + // +5, (white) + // gnd, (black) + + cortex_m::asm::dsb(); // chip errata + let gpiob = device.GPIOB.split(); + cortex_m::asm::dsb(); // chip errata + let gpioc = device.GPIOC.split(); + cortex_m::asm::dsb(); // chip errata + + let sck = gpiob.pb10.into_alternate_af5().set_speed(Speed::VeryHigh); + let miso = gpioc.pc2.into_alternate_af5().set_speed(Speed::High); + let mosi = gpioc.pc3.into_alternate_af5().set_speed(Speed::High); + let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High); + + let spi = Spi::spi2( + device.SPI2, + (sck, miso, mosi), + MODE_3, + stm32f4xx_hal::time::KiloHertz(2000).into(), + clocks, + ); + + let delay = DwtDelay::new(&mut core.DWT, clocks); + let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap(); + + // // set in burst mode + // pmw3389.write_register(Register::MotionBurst, 0x00).unwrap(); + + // setup TIM1 as PWM (for implementing an 8 bit DA) + let gpioa = device.GPIOA.split(); + cortex_m::asm::dsb(); // chip errata + // we set the pins to VeryHigh to get the sharpest waveform possible // (rise and fall times should have similar characteristics) let _channels = ( @@ -55,7 +124,7 @@ const APP: () = { ); // Setup PWM RAW - let tim1 = dp.TIM1; + let tim1 = device.TIM1; // Here we need unsafe as we are "stealing" the RCC peripheral // At this point it has been contrained into SysConf and used to set clocks let rcc = unsafe { &(*stm32::RCC::ptr()) }; @@ -77,7 +146,7 @@ const APP: () = { tim1.cr1.modify(|_, w| w.arpe().set_bit()); let clk = clocks.pclk2().0 * if clocks.ppre2() == 1 { 1 } else { 2 }; - // check that its actually 48_000_000 + // check the actual clock setup rprintln!("clk {}", clk); // we want maximum performance, thus we set the prescaler to 0 @@ -128,18 +197,20 @@ const APP: () = { tim1.dier.write(|w| w.uie().enabled()); tim1.sr.modify(|_, w| w.uif().clear()); - // Set divider to 4, (48_000_000/256)/4 - // tim1.rcr.modify(|_, w| unsafe { w.rep().bits(4) }); - + // just to check that we actually get update events while tim1.sr.read().uif().is_clear() { rprint!("-"); } rprintln!("here"); tim1.sr.modify(|_, w| w.uif().clear()); + cx.schedule.pwm_out(cx.start + PWM_CYCLES.cycles()).ok(); + cx.schedule.poll(cx.start + POLL_CYCLES.cycles()).ok(); // pass on late resources - cx.schedule.pwm_out(cx.start + PERIOD.cycles()).ok(); - init::LateResources { TIM1: tim1 } + init::LateResources { + TIM1: tim1, + pmw3389, + } } #[idle] @@ -147,41 +218,98 @@ const APP: () = { rprintln!("idle"); // panic!("panic"); loop { - continue; + asm::nop() + } + } + + #[task(priority = 1)] + fn trace(_cx: trace::Context, pos_x: i64, pos_y: i64) { + static mut OLD_POS_X: i64 = 0; + static mut OLD_POS_Y: i64 = 0; + rprintln!( + "@{:?}, pos_x {:010}, diff {:010}, pos_y {:010}, diff {:010} ", + Instant::now(), + pos_x, + pos_x.wrapping_sub(*OLD_POS_X), + pos_y, + pos_y.wrapping_sub(*OLD_POS_Y), + ); + *OLD_POS_X = pos_x; + *OLD_POS_Y = pos_y; + } + + #[task(priority = 2, resources = [pmw3389], schedule = [poll], spawn = [trace])] + fn poll(cx: poll::Context) { + static mut COUNTER: u32 = 0; + static mut POS_X: i64 = 0; + static mut POS_Y: i64 = 0; + + // run each ms + *COUNTER += 1; + if *COUNTER == 1000 { + // run each s + cx.spawn.trace(*POS_X, *POS_Y).unwrap(); + *COUNTER = 0; } + + let pmw3389 = cx.resources.pmw3389; + + //write 0x01 to Motion register and read from it to freeze the motion values and make them available + pmw3389.write_register(Register::Motion, 0x01).unwrap(); + let _ = pmw3389.read_register(Register::Motion).unwrap(); + + let xl: u8 = pmw3389.read_register(Register::DeltaXL).unwrap(); + let xh: u8 = pmw3389.read_register(Register::DeltaXH).unwrap(); + let yl = pmw3389.read_register(Register::DeltaYL).unwrap(); + let yh = pmw3389.read_register(Register::DeltaYH).unwrap(); + + // let (x, _y) = cx.resources.pmw3389.read_status().unwrap(); + *POS_X += (((xl as u16) | ((xh as u16) << 8)) as i16) as i64; + *POS_Y += (((yl as u16) | ((yh as u16) << 8)) as i16) as i64; + + // task should run each second N ms (96_000 cycles at 96MHz) + cx.schedule + .poll(cx.scheduled + POLL_CYCLES.cycles()) + .unwrap(); } - #[task(resources = [TIM1], schedule = [pwm_out])] + #[task(priority = 3, resources = [TIM1], schedule = [pwm_out])] fn pwm_out(cx: pwm_out::Context) { static mut INDEX: u16 = 0; static mut LEFT: u16 = 0; static mut RIGHT: u16 = 0; - static mut FLOAT: u16 = 0; + // static mut FLOAT: u16 = 0; let tim1 = cx.resources.TIM1; tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) }); - // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) }); - tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) }); + tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) }); + // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) }); + + cx.schedule + .pwm_out(cx.scheduled + PWM_CYCLES.cycles()) + .unwrap(); - *INDEX = (*INDEX).wrapping_add(10_000); - let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0; - *FLOAT = (128.0 + f.sin() * 128.0) as u16; - cx.schedule.pwm_out(cx.scheduled + PERIOD.cycles()).ok(); + *INDEX = (*INDEX).wrapping_add(1_000); + // let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0; + // *FLOAT = (128.0 + f.sin() * 128.0) as u16; *LEFT = SINE_BUF[*INDEX as usize] as u16; *RIGHT = SINE_BUF[*INDEX as usize] as u16; - if cx.scheduled.elapsed() > 500.cycles() { - panic!("task overrun"); - } + // if cx.scheduled.elapsed() > 1500.cycles() { + // panic!("task overrun"); + // } } extern "C" { fn EXTI0(); + fn EXTI1(); + fn EXTI2(); } }; // We aim for a sampling rate of 48kHz, assuming that the input filter of the // sound card used to sample the generated signal has an appropriate input filter -const PERIOD: u32 = 2000; // 96_000_000 / 48_000; +const PWM_CYCLES: u32 = 2000; // 96_000_000 / 2_000 = 48_000 Hz +const POLL_CYCLES: u32 = 96_000; // 96_000_000 / 96_000 = 1_000 Hz diff --git a/examples/rtt-pwm-sine-task.rs b/examples/rtt-pwm-sine-task.rs index 4858241..0aae89b 100644 --- a/examples/rtt-pwm-sine-task.rs +++ b/examples/rtt-pwm-sine-task.rs @@ -6,14 +6,17 @@ #![no_main] #![no_std] -use core::f32::consts::PI; +// use core::f32::consts::PI; use cortex_m::{asm, peripheral::DWT}; // use panic_halt as _; use panic_rtt_target as _; use rtic::cyccnt::{Instant, U32Ext as _}; use rtt_target::{rprint, rprintln, rtt_init_print}; -use stm32f4xx_hal::{bb, dma, gpio::Speed, prelude::*, pwm, stm32}; +use core::f32::consts::PI; +use micromath::F32Ext; + +use stm32f4xx_hal::{bb, gpio::Speed, prelude::*, pwm, stm32}; include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs")); @@ -153,19 +156,23 @@ const APP: () = { static mut INDEX: u16 = 0; static mut LEFT: u16 = 0; static mut RIGHT: u16 = 0; + static mut FLOAT: u16 = 0; let tim1 = cx.resources.TIM1; tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) }); - tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) }); + // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) }); + tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) }); *INDEX = (*INDEX).wrapping_add(10_000); + let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0; + *FLOAT = (128.0 + f.sin() * 128.0) as u16; cx.schedule.pwm_out(cx.scheduled + PERIOD.cycles()).ok(); *LEFT = SINE_BUF[*INDEX as usize] as u16; *RIGHT = SINE_BUF[*INDEX as usize] as u16; - if cx.scheduled.elapsed() > 300.cycles() { + if cx.scheduled.elapsed() > 500.cycles() { panic!("task overrun"); } } diff --git a/examples/rtt-pwm-sine.rs b/examples/rtt-pwm-sine.rs index 726f5cb..e9fdb2e 100644 --- a/examples/rtt-pwm-sine.rs +++ b/examples/rtt-pwm-sine.rs @@ -47,7 +47,7 @@ const APP: () = { // Setup PWM RAW let tim1 = dp.TIM1; // Here we need unsafe as we are "stealing" the RCC peripheral - // At this point it has been contrained into SysConf and used to set clocks + // At this point it has been constrained into SysConf and used to set clocks let rcc = unsafe { &(*stm32::RCC::ptr()) }; rcc.apb2enr.modify(|_, w| w.tim1en().set_bit()); diff --git a/examples/rtt-timing.rs b/examples/rtt-timing.rs index 720e799..7e1ee06 100644 --- a/examples/rtt-timing.rs +++ b/examples/rtt-timing.rs @@ -1,8 +1,8 @@ //! examples/rtt_timing.rs //! cargo run --examples rtt-timing -#![deny(unsafe_code)] -#![deny(warnings)] +// #![deny(unsafe_code)] +// #![deny(warnings)] #![no_main] #![no_std] diff --git a/examples/rtt_rtic_i2c.rs b/examples/rtt_rtic_i2c.rs index c3bca53..e057177 100644 --- a/examples/rtt_rtic_i2c.rs +++ b/examples/rtt_rtic_i2c.rs @@ -6,7 +6,6 @@ #![no_std] use cortex_m::{asm::delay, delay}; -// use panic_halt as _; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; @@ -21,15 +20,36 @@ use stm32f4xx_hal::{ stm32::I2C1, }; +use rtic::cyccnt::{Instant, U32Ext as _}; + use app::{ pmw3389e::{self, Register}, DwtDelay, }; -#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)] +const OFFSET: u32 = 8_000_000 / 10; +const LOG_OFFSET: u32 = 8_000_000; + +#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] const APP: () = { - #[init] - fn init(cx: init::Context) { + struct Resources { + pmw3389: pmw3389e::Pmw3389e< + SC18IS602::SH18IS602< + I2c< + I2C1, + ( + PB8<AlternateOD<stm32f4xx_hal::gpio::AF4>>, + PB9<AlternateOD<stm32f4xx_hal::gpio::AF4>>, + ), + >, + >, + SC18IS602::Error, + >, + #[init((0, 0))] + pos: (i64, i64), + } + #[init(schedule = [poll, log])] + fn init(cx: init::Context) -> init::LateResources { rtt_init_print!(); rprintln!("init"); let dp = cx.device; @@ -41,6 +61,7 @@ const APP: () = { // Initialize (enable) the monotonic timer (CYCCNT) cp.DCB.enable_trace(); + cp.DWT.enable_cycle_counter(); // Set up I2C. let gpiob = dp.GPIOB.split(); @@ -52,54 +73,17 @@ const APP: () = { use embedded_hal::spi::MODE_3; use SC18IS602::{Order, Speed, SH18IS602}; - let mut spi_emu = - SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true); + let spi_emu = SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true); rprintln!("spi_emu initialized"); - // reset SPI transfer - spi_emu.set_low().ok(); - cortex_m::asm::delay(1_000_000); - spi_emu.set_high().ok(); - cortex_m::asm::delay(1_000_000); - - rprintln!("set to gpio management"); - - // try split transaction - rprintln!("try split transaction"); - // the write part - spi_emu.set_low().unwrap(); - let mut req = [0x00]; - spi_emu.transfer(&mut req).unwrap(); - rprintln!("id request {:02x?}", req); - - cortex_m::asm::delay(1_000); - // the read part - let mut req = [00]; - spi_emu.transfer(&mut req).unwrap(); - rprintln!("id resp {:02x?}", req); - - spi_emu.set_high().unwrap(); - - rprintln!("try split transaction"); - // the write part - spi_emu.set_low().unwrap(); - let mut req = [0x01]; - spi_emu.transfer(&mut req).unwrap(); - rprintln!("version request {:02x?}", req); - - cortex_m::asm::delay(1_000); - // the read part - let mut req = [00]; - spi_emu.transfer(&mut req).unwrap(); - rprintln!("version resp {:02x?}", req); - - spi_emu.set_high().unwrap(); - let delay = DwtDelay::new(&mut cp.DWT, clocks); let pmw3389 = pmw3389e::Pmw3389e::new(spi_emu, delay).unwrap(); rprintln!("success"); + cx.schedule.poll(cx.start + OFFSET.cycles()).unwrap(); + cx.schedule.log(cx.start + LOG_OFFSET.cycles()).unwrap(); + init::LateResources { pmw3389 } } #[idle] @@ -109,6 +93,52 @@ const APP: () = { continue; } } + + #[task(priority = 2, resources = [pmw3389, pos], schedule = [poll])] + fn poll(cx: poll::Context) { + // rprintln!("poll @ {:?}", Instant::now()); + + // static mut X: i64 = 0; + // static mut Y: i64 = 0; + + cx.schedule.poll(cx.scheduled + OFFSET.cycles()).unwrap(); + let pmw3389 = cx.resources.pmw3389; + + pmw3389.write_register(Register::Motion, 0x01).unwrap(); + + let motion = pmw3389.read_register(Register::Motion).unwrap(); + let xl = pmw3389.read_register(Register::DeltaXL).unwrap(); + let xh = pmw3389.read_register(Register::DeltaXH).unwrap(); + let yl = pmw3389.read_register(Register::DeltaYL).unwrap(); + let yh = pmw3389.read_register(Register::DeltaYH).unwrap(); + + let x = (xl as u16 + (xh as u16) << 8) as i16; + let y = (yl as u16 + (yh as u16) << 8) as i16; + + cx.resources.pos.0 += x as i64; + cx.resources.pos.1 += y as i64; + + // let surface = motion & 0x08; + // let motion_detect = motion & 0x80; + + // rprintln!( + // "motion {}, surface {}, (x, y) {:?}", + // motion_detect, + // surface, + // (x, y), + // ); + } + + #[task(priority = 1, resources = [pos], schedule = [log])] + fn log(mut cx: log::Context) { + cx.schedule.log(cx.scheduled + LOG_OFFSET.cycles()).unwrap(); + cx.resources.pos.lock(|pos| rprintln!("(x, y) {:?}", pos)); + } + + extern "C" { + fn EXTI0(); + fn EXTI1(); + } }; // SC18IS602 @@ -222,8 +252,12 @@ mod SC18IS602 { | (mode.phase as u8) << 2 | speed as u8; + rprintln!("configuring i2c->spi bridge"); + device.i2c.write(addr, &mut [SpiConfigure.id(), cfg]).ok(); + rprintln!("spi bridge configured"); + if gpio { device.set_ss0_gpio(); } else { @@ -258,8 +292,6 @@ mod SC18IS602 { } } - // impl<I2C> Default for SH18IS602<I2C> where I2C: i2c::Write + i2c::Read {} - impl<I2C> Transfer<u8> for SH18IS602<I2C> where I2C: i2c::Write + i2c::Read, @@ -290,12 +322,10 @@ mod SC18IS602 { // A short delay is needed // For improved performance use write if result is not needed - cortex_m::asm::delay(1000); + cortex_m::asm::delay(1_000); self.i2c.read(self.addr, words).map_err(|_| panic!()).ok(); - // rprintln!("transfer_read {:02x?}", words); - Ok(words) } } @@ -310,12 +340,13 @@ mod SC18IS602 { if !self.gpio { Err(Error::NotConfigured) } else { - rprintln!("set low"); + // rprintln!("set low"); + // cortex_m::asm::delay(10_000); self.i2c .write(self.addr, &[Function::GpioWrite.id(), 0x0]) .map_err(|_| panic!()) .ok(); - cortex_m::asm::delay(100_000); + // cortex_m::asm::delay(20_000); Ok(()) } } @@ -324,7 +355,8 @@ mod SC18IS602 { if !self.gpio { Err(Error::NotConfigured) } else { - rprintln!("set_high"); + // rprintln!("set_high"); + // cortex_m::asm::delay(10_000); self.i2c .write(self.addr, &[Function::GpioWrite.id(), 0x1]) .map_err(|_| panic!()) diff --git a/examples/rtt_rtic_usb_mouse.rs b/examples/rtt_rtic_usb_mouse.rs index 7bb3347..23bfa4e 100644 --- a/examples/rtt_rtic_usb_mouse.rs +++ b/examples/rtt_rtic_usb_mouse.rs @@ -324,6 +324,7 @@ fn usb_poll<B: bus::UsbBus>( usb_dev: &mut UsbDevice<'static, B>, hid: &mut HIDClass<'static, B>, ) { + // if !usb_dev.poll(&mut [hid]) { return; } diff --git a/examples/usb-mouse.rs b/examples/usb-mouse.rs index 8ce3148..fef110b 100644 --- a/examples/usb-mouse.rs +++ b/examples/usb-mouse.rs @@ -9,6 +9,7 @@ use stm32f4xx_hal::{ gpio::{gpioc::PC13, Input, PullUp}, otg_fs::{UsbBus, UsbBusType, USB}, prelude::*, + rcc::Clocks, }; use usb_device::{bus::UsbBusAllocator, prelude::*}; use usbd_hid::{ @@ -37,7 +38,8 @@ const APP: () = { // Set up the system clock. let rcc = ctx.device.RCC.constrain(); - let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + let clocks: Clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + let hclk = clocks.hclk(); let gpioc = ctx.device.GPIOC.split(); let btn = gpioc.pc13.into_pull_up_input(); @@ -49,6 +51,7 @@ const APP: () = { usb_pwrclk: ctx.device.OTG_FS_PWRCLK, pin_dm: gpioa.pa11.into_alternate_af10(), pin_dp: gpioa.pa12.into_alternate_af10(), + hclk, }; USB_BUS.replace(UsbBus::new(usb, EP_MEMORY)); @@ -66,6 +69,12 @@ const APP: () = { #[task(binds=OTG_FS, resources = [btn, hid, usb_dev])] fn on_usb(ctx: on_usb::Context) { static mut COUNTER: u16 = 0; + static mut FIRST: bool = true; + + if *FIRST { + rprintln!("on_usb"); + *FIRST = false; + } // destruct the context let (btn, usb_dev, hid) = (ctx.resources.btn, ctx.resources.usb_dev, ctx.resources.hid); @@ -104,7 +113,7 @@ const APP: () = { fn idle(_cx: idle::Context) -> ! { rprintln!("idle"); loop { - continue; + cortex_m::asm::nop(); } } }; diff --git a/openocd.gdb b/openocd.gdb index 1623a86..01b500c 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -24,7 +24,7 @@ monitor arm semihosting enable # # send captured ITM to the file itm.fifo # # (the microcontroller SWO pin must be connected to the programmer SWO pin) # # 8000000 must match the core clock frequency -monitor tpiu config internal itm.txt uart off 16000000 +monitor tpiu config internal itm.txt uart off 48000000 # # OR: make the microcontroller SWO pin output compatible with UART (8N1) # # 8000000 must match the core clock frequency diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 7922596..0000000 --- a/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![no_std] -#![no_main] - -// pick a panicking behavior -use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics -// use panic_abort as _; // requires nightly -// use panic_itm as _; // logs messages over ITM; requires ITM support -// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger - -use cortex_m::asm; -use cortex_m_rt::entry; - -#[entry] -fn main() -> ! { - asm::nop(); // To not have main optimize to abort in release mode, remove when you add code - - loop { - // your code goes here - } -} diff --git a/src/pmw3389.rs b/src/pmw3389.rs index a978c32..e2823f6 100644 --- a/src/pmw3389.rs +++ b/src/pmw3389.rs @@ -6,7 +6,7 @@ use crate::DwtDelay; use embedded_hal::blocking::spi::{Transfer, Write}; use embedded_hal::digital::v2::OutputPin; -use rtt_target::{rprint, rprintln}; +use rtt_target::rprintln; #[allow(dead_code)] #[derive(Clone, Copy)] @@ -116,23 +116,6 @@ where rprintln!("reset"); - // shutdown - - // adns_write_reg(Shutdown, 0xb6); // Shutdown first - // delay(300); - - // adns_com_begin(); // drop and raise ncs to reset spi port - // delayMicroseconds(40); - // adns_com_end(); - // delayMicroseconds(40); - - // pmw3389.write_register(Register::Shutdown, 0xb6)?; - // pmw3389.delay.delay_ms(300); - // pmw3389.com_begin(); - // pmw3389.delay.delay_us(40); - // pmw3389.com_end(); - // pmw3389.delay.delay_us(40); - // force reset pmw3389.write_register(Register::PowerUpReset, 0x5a)?; @@ -220,7 +203,7 @@ where } /// Read status - pub fn read_status(&mut self) -> Result<((i16, i16)), E> { + pub fn read_status(&mut self) -> Result<(i16, i16), E> { self.com_begin(); self.spi.transfer(&mut [Register::MotionBurst.addr()])?; @@ -340,7 +323,7 @@ where // // set initial CPI resolution // // adns_write_reg(Config1, 0x15); - let cpi: u16 = 16000; + let cpi: u16 = 1600; self.write_register(Register::ResolutionL, cpi as u8)?; self.write_register(Register::ResolutionH, (cpi >> 8) as u8)?; diff --git a/src/pmw3389e.rs b/src/pmw3389e.rs index 2455b25..6a77599 100644 --- a/src/pmw3389e.rs +++ b/src/pmw3389e.rs @@ -146,16 +146,16 @@ where pmw3389.upload_firmware()?; - // pmw3389.delay.delay_ms(1000); + pmw3389.delay.delay_ms(1000); - // rprintln!("Optical Chip Initialized"); + rprintln!("Optical Chip Initialized"); - // // read product id - // let id = pmw3389.product_id()?; - // rprintln!("product_id 0x{:x}", id); + // read product id + let id = pmw3389.product_id()?; + rprintln!("product_id 0x{:x}", id); - // let srom_id = pmw3389.read_register(Register::SROMId)?; - // rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id); + let srom_id = pmw3389.read_register(Register::SROMId)?; + rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id); // // loop { // // pmw3389.write_register(Register::Motion, 0x01)?; @@ -384,7 +384,7 @@ where // // adns_write_reg(Config1, 0x15); // self.write_register(Register::ResolutionL, 0x15)?; - self.write_register(Register::ResolutionL, 0x5)?; + self.write_register(Register::ResolutionL, 0x15)?; // self.write_register(Register::ResolutionH, 0x15)?; self.write_register(Register::ResolutionH, 0x00)?; -- GitLab