Skip to content
Snippets Groups Projects
Select Git revision
  • 5e2f0e81bb2bccfb08341a06c06e45fb78fd49ca
  • master default protected
2 results

pmw3389.rs

Blame
  • pmw3389.rs 3.91 KiB
    #![deny(unsafe_code)]
    // #![deny(warnings)]
    #![no_main]
    #![no_std]
    
    use embedded_hal::spi::MODE_3;
    use panic_rtt_target as _;
    
    use rtic::cyccnt::{Instant, U32Ext as _};
    use stm32f4xx_hal::{
        dwt::Dwt,
        gpio::Speed,
        gpio::{
            gpiob::{PB10, PB4},
            gpioc::{PC2, PC3},
            Alternate, Output, PushPull,
        },
        prelude::*,
        rcc::Clocks,
        spi::Spi,
        stm32,
    };
    
    use app::{
        pmw3389::{self, Register},
        DwtDelay,
    };
    use rtt_target::{rprintln, rtt_init_print};
    
    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>>,
    >;
    
    #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
    const APP: () = {
        struct Resources {
            // late resources
            pmw3389: PMW3389T,
        }
        #[init(schedule = [poll])]
        fn init(cx: init::Context) -> init::LateResources {
            rtt_init_print!();
            rprintln!("init");
    
            let mut core = cx.core;
            let device = cx.device;
    
            // Initialize (enable) the monotonic timer (CYCCNT)
            core.DCB.enable_trace();
            core.DWT.enable_cycle_counter();
    
            // setup clocks
            let rcc = device.RCC.constrain();
            let clocks = rcc.cfgr.freeze();
            rprintln!("clocks:");
            rprintln!("hclk {}", clocks.hclk().0);
    
            // Configure SPI
            // spi2
            // sck    - pb10, (yellow)
            // miso   - pc2, (red)
            // mosi   - pc3, (orange)
            // ncs    - pb4, (long yellow)
            // motion - (brown)
            //
            // +5, (white)
            // gnd, (black)
    
            let gpiob = device.GPIOB.split();
            let gpioc = device.GPIOC.split();
    
            let sck = gpiob.pb10.into_alternate_af5();
            let miso = gpioc.pc2.into_alternate_af5();
            let mosi = gpioc.pc3.into_alternate_af5();
            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(200).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();
    
            // 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
            let now = cx.start; // the start time of the system
    
            cx.schedule.poll(now + 16_000.cycles()).unwrap();
    
            // pass on late resources
            init::LateResources { pmw3389 }
        }
    
        #[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;
    
            // run each ms
            *COUNTER += 1;
            if *COUNTER == 1000 {
                // run each s
                cx.spawn.trace(*POS_X).unwrap();
                *COUNTER = 0;
            }
    
            let (x, _y) = cx.resources.pmw3389.read_status().unwrap();
            *POS_X += x as i64;
    
            // task should run each second N ms (16_000 cycles at 16MHz)
            cx.schedule.poll(cx.scheduled + 16_000.cycles()).unwrap();
        }
    
        #[task(priority = 1)]
        fn trace(_cx: trace::Context, pos: i64) {
            static mut OLD_POS: i64 = 0;
            rprintln!(
                "pos_x {:010}, diff {:010} @{:?}",
                pos,
                pos - *OLD_POS,
                Instant::now()
            );
            *OLD_POS = pos;
        }
    
        #[idle]
        fn idle(_cx: idle::Context) -> ! {
            loop {
                continue;
            }
        }
    
        extern "C" {
            fn EXTI0();
            fn EXTI1();
        }
    };
    
    const RATIO: u32 = 5;