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

rtt-pwm-dma.rs

Blame
  • rtt-pwm-dma.rs 5.14 KiB
    //! examples/rtt-pwm-dma.rs
    //! cargo run --examples rtt-pwm-dma
    
    // #![deny(unsafe_code)]
    // #![deny(warnings)]
    #![no_main]
    #![no_std]
    
    use cortex_m::{asm, peripheral::DWT};
    use panic_halt as _;
    use rtt_target::{rprintln, rtt_init_print};
    use stm32f4xx_hal::{bb, dma, gpio::Speed, prelude::*, pwm, stm32};
    
    #[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
    const APP: () = {
        #[init]
        fn init(mut cx: init::Context) {
            rtt_init_print!();
            rprintln!("init");
            let dp = cx.device;
    
            // 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())
                .pclk1(24.mhz())
                .freeze();
    
            let gpioa = dp.GPIOA.split();
            // we set the pins to VeryHigh to get the sharpest waveform possible
            // (rise and fall times should have similar characteristics)
            let channels = (
                gpioa.pa8.into_alternate_af1().set_speed(Speed::VeryHigh),
                gpioa.pa9.into_alternate_af1().set_speed(Speed::VeryHigh),
            );
    
            // 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
            let rcc = unsafe { &(*stm32::RCC::ptr()) };
    
            // pwm_all_channels!(TIM1: (tim1, apb2enr, apb2rstr, 0u8, pclk2, ppre2));
    
            // Enable and reset the timer peripheral,
            // it's the same bit position for both registers (0 in this case)
            // Notice the use of bit banding to set/clear bits individually
            // It is unsafe, as the register address could be anything within range
            // of the bitband region
            unsafe {
                bb::set(&rcc.apb2enr, 0u8);
                bb::set(&rcc.apb2rstr, 0u8);
                bb::clear(&rcc.apb2rstr, 0u8);
            }
            // Setup chanel 1 and 2 as pwm_mode1
            tim1.ccmr1_output()
                .modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1());
    
            tim1.ccmr1_output()
                .modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1());
    
            // The reference manual is a bit ambiguous about when enabling this bit is really
            // necessary, but since we MUST enable the preload for the output channels then we
            // might as well enable for the auto-reload too
            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
            rprintln!("clk {}", clk);
    
            // we want maximum performance, thus we set the prescaler to 0
            let pre = 0;
            rprintln!("pre {}", pre);
            tim1.psc.write(|w| w.psc().bits(pre));
    
            // we want 8 bits of resolution
            // so our ARR = 2^8 - 1 = 256 - 1 = 255
            let arr = 255;
            rprintln!("arr {}", arr);
            tim1.arr.write(|w| unsafe { w.bits(arr) });
    
            //  Trigger update event to load the registers
            tim1.cr1.modify(|_, w| w.urs().set_bit());
            tim1.egr.write(|w| w.ug().set_bit());
            tim1.cr1.modify(|_, w| w.urs().clear_bit());
    
            // Set main output enable of all Output Compare (OC) registers
            tim1.bdtr.modify(|_, w| w.moe().set_bit());
    
            // Set output enable for channels 1 and 2
            // Channel 1 (bit  0)
            unsafe { bb::set(&tim1.ccer, 0) }
            // Channel 4 (bit  0)
            unsafe { bb::set(&tim1.ccer, 4) }
    
            // Setup the timer
            tim1.cr1.write(|w| {
                w.cms()
                    .bits(0b00) // edge aligned mode
                    .dir() // counter used as upcounter
                    .clear_bit()
                    .opm() // one pulse mode
                    .clear_bit()
                    .cen() // enable counter
                    .set_bit()
            });
    
            // Set duty cycle of Channels
            tim1.ccr1.write(|w| unsafe { w.ccr().bits(128) });
            tim1.ccr2.write(|w| unsafe { w.ccr().bits(128) });
    
            // Set preload for the CCx
            tim1.cr2.write(|w| w.ccpc().set_bit());
    
            tim1.dier.write(|w| w.uie().enabled());
    
            loop {
                for i in 0..255 {
                    tim1.ccr1.write(|w| unsafe { w.ccr().bits(i) });
                    tim1.ccr2.write(|w| unsafe { w.ccr().bits(i) });
                    // rprintln!("-");
                    //while tim1.sr.read().uif().is_clear() {
                    while !tim1.sr.read().uif().is_clear() {
                        rprintln!("-");
                    }
                    // rprintln!("!");
                }
            }
        }
    
        #[idle]
        fn idle(_cx: idle::Context) -> ! {
            rprintln!("idle");
            loop {
                continue;
            }
        }
    };
    
    mod dma_pwm {
        // Not sure we need a dma mode
        // DMA mode
        // #[derive(Debug, Clone, Copy)]
        // pub enum Dma {
        //     /// No DMA, disabled
        //     Disabled,
        //     /// Single DMA, DMA will be disabled after each conversion sequence
        //     Single,
        //     /// Continuous DMA, DMA will remain enabled after conversion
        //     Continuous,
        // }
    }