From 98c8c8d8b4f13bceb3077f5d9b1635dafe40e17f Mon Sep 17 00:00:00 2001 From: jsjolund <j.sjolund@gmail.com> Date: Sat, 9 Dec 2017 17:57:39 +0100 Subject: [PATCH] Pwm control, fix examples --- examples/blinky.rs | 6 +- examples/concurrency.rs | 21 ++- examples/led.rs | 8 +- examples/preemption.rs | 4 +- examples/pwm-control.rs | 90 +++++++++++ examples/pwm1.rs | 2 +- examples/resource.rs | 4 +- examples/roulette.rs | 4 +- src/dma.rs | 141 +++++++++++++++- src/leds.rs | 57 +++++++ src/lib.rs | 3 +- src/pwm.rs | 348 ++++++++++++++++++++++++++++------------ 12 files changed, 554 insertions(+), 134 deletions(-) create mode 100644 examples/pwm-control.rs create mode 100644 src/leds.rs diff --git a/examples/blinky.rs b/examples/blinky.rs index 63b927e..8e45401 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -9,7 +9,7 @@ extern crate cortex_m; extern crate cortex_m_rtfm as rtfm; use cortex_m::peripheral::SystClkSource; -use f4::led::{self, LEDS}; +use f4::led::{self, LED}; use rtfm::{app, Threshold}; // CONFIGURATION @@ -55,8 +55,8 @@ fn toggle(_t: &mut Threshold, r: SYS_TICK::Resources) { **r.ON = !**r.ON; if **r.ON { - LEDS[0].on(); + LED.on(); } else { - LEDS[0].off(); + LED.off(); } } diff --git a/examples/concurrency.rs b/examples/concurrency.rs index 624591a..44b6fbb 100644 --- a/examples/concurrency.rs +++ b/examples/concurrency.rs @@ -10,12 +10,11 @@ extern crate cortex_m_rtfm as rtfm; extern crate f4; use f4::Serial; -use f4::led::{self, LEDS}; +use f4::led::{self, LED}; use f4::prelude::*; use f4::serial::Event; use f4::time::Hertz; use cortex_m::peripheral::SystClkSource; -use cast::{usize, u8}; use rtfm::{app, Threshold}; // CONFIGURATION @@ -28,13 +27,13 @@ app! { device: f4::stm32f40x, resources: { - static STATE: u8 = 0; + static ON: bool = false; }, tasks: { SYS_TICK: { path: roulette, - resources: [STATE], + resources: [ON], }, USART2: { @@ -46,7 +45,7 @@ app! { // INITIALIZATION PHASE fn init(p: init::Peripherals, _r: init::Resources) { - led::init(p.GPIOB, p.RCC); + led::init(p.GPIOA, p.RCC); let serial = Serial(p.USART2); serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC); @@ -85,11 +84,11 @@ fn loopback(_t: &mut Threshold, r: USART2::Resources) { } fn roulette(_t: &mut Threshold, r: SYS_TICK::Resources) { - let curr = **r.STATE; - let next = (curr + 1) % u8(LEDS.len()).unwrap(); + **r.ON = !**r.ON; - LEDS[usize(curr)].off(); - LEDS[usize(next)].on(); - - **r.STATE = next; + if **r.ON { + LED.on(); + } else { + LED.off(); + } } diff --git a/examples/led.rs b/examples/led.rs index fca8d7b..dfdc880 100644 --- a/examples/led.rs +++ b/examples/led.rs @@ -7,7 +7,7 @@ extern crate cortex_m_rtfm as rtfm; extern crate f4; -use f4::led::{self, LEDS}; +use f4::led::{self, LED}; use rtfm::app; // TASKS & RESOURCES @@ -22,12 +22,10 @@ fn init(p: init::Peripherals) { // IDLE LOOP fn idle() -> ! { - for led in &LEDS { - led.on(); - } - // Sleep loop { + LED.on(); rtfm::wfi(); + LED.off(); } } diff --git a/examples/preemption.rs b/examples/preemption.rs index d8937a7..62e7d36 100644 --- a/examples/preemption.rs +++ b/examples/preemption.rs @@ -21,7 +21,7 @@ extern crate heapless; use cast::{usize, u8}; use cortex_m::peripheral::SystClkSource; use f4::Serial; -use f4::led::{self, LEDS}; +use f4::leds::{LEDS}; use f4::prelude::*; use f4::serial::Event; use heapless::Vec; @@ -59,7 +59,7 @@ app!{ // INITIALIZATION PHASE fn init(p: init::Peripherals, _r: init::Resources) { - led::init(&p.GPIOA, &p.RCC); + f4::leds::init(&p.GPIOB, &p.RCC); let serial = Serial(p.USART2); serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC); diff --git a/examples/pwm-control.rs b/examples/pwm-control.rs new file mode 100644 index 0000000..8f3a4cc --- /dev/null +++ b/examples/pwm-control.rs @@ -0,0 +1,90 @@ +//! Output a PWM on pin PA0 and control its duty cycle via a serial interface +//! +//! - '*' increase duty by a factor of 2 +//! - '+' increase duty by 1 +//! - '-' decrease duty by 1 +//! - '/' decrease duty by a factor of 2 +#![deny(unsafe_code)] +#![deny(warnings)] +#![feature(proc_macro)] +#![no_std] + +extern crate f4; +extern crate cortex_m_rtfm as rtfm; + +use core::u32; + +use f4::prelude::*; +use f4::time::Hertz; +use f4::{Channel, Pwm, Serial}; +use f4::serial::Event; +use rtfm::{app, Threshold}; + +const BAUD_RATE: Hertz = Hertz(115_200); +const FREQUENCY: Hertz = Hertz(1_000); + +app! { + device: f4::stm32f40x, + + tasks: { + USART2: { + path: rx, + resources: [TIM4, USART2], + }, + }, +} + +fn init(p: init::Peripherals) { + let pwm = Pwm(p.TIM4); + let serial = Serial(p.USART2); + + serial.init(BAUD_RATE.invert(), None, p.GPIOA, p.RCC); + serial.listen(Event::Rxne); + + pwm.init(FREQUENCY.invert(), None, p.GPIOA, p.GPIOB, p.GPIOC, p.RCC); + pwm.set_duty(Channel::_1, 0); + + pwm.enable(Channel::_1); +} + +fn idle() -> ! { + loop { + rtfm::wfi(); + } +} + +fn rx(_t: &mut Threshold, r: USART2::Resources) { + let pwm = Pwm(&**r.TIM4); + let serial = Serial(&**r.USART2); + + let byte = serial.read().unwrap(); + // Echo back to signal we are alive + serial.write(byte).unwrap(); + + match byte { + b'+' | b'-' | b'*' | b'/' => { + let duty = pwm.get_duty(Channel::_1); + + match byte { + b'+' => { + let max = pwm.get_max_duty(); + pwm.set_duty(Channel::_1, if duty < max { duty + 1 } else { max }); + } + b'-' => { + pwm.set_duty(Channel::_1, duty.checked_sub(1).unwrap_or(0)); + } + b'*' => { + let new_duty = duty.checked_mul(2).unwrap_or(u32::MAX); + let max_duty = pwm.get_max_duty(); + + if new_duty < max_duty { + pwm.set_duty(Channel::_1, new_duty) + } + } + b'/' => pwm.set_duty(Channel::_1, duty / 2), + _ => { /* unreachable */ } + } + } + _ => {} + } +} \ No newline at end of file diff --git a/examples/pwm1.rs b/examples/pwm1.rs index f939fd4..60ca459 100644 --- a/examples/pwm1.rs +++ b/examples/pwm1.rs @@ -21,7 +21,7 @@ app! { } fn init(p: init::Peripherals) { - let pwm = Pwm(p.TIM3); + let pwm = Pwm(p.TIM1); pwm.init(FREQUENCY.invert(), None, p.GPIOA,p.GPIOB,p.GPIOC, p.RCC); let duty = pwm.get_max_duty() / 16; diff --git a/examples/resource.rs b/examples/resource.rs index c39e71e..51127fd 100644 --- a/examples/resource.rs +++ b/examples/resource.rs @@ -24,7 +24,7 @@ extern crate heapless; use cast::{usize, u8}; use cortex_m::peripheral::SystClkSource; use f4::Serial; -use f4::led::{self, LEDS}; +use f4::leds::{LEDS}; use f4::prelude::*; use f4::serial::Event; use f4::time::Hertz; @@ -61,7 +61,7 @@ app! { // INITIALIZATION PHASE fn init(p: init::Peripherals, _r: init::Resources) { - led::init(&p.GPIOA, &p.RCC); + f4::leds::init(&p.GPIOB, &p.RCC); let serial = Serial(p.USART2); serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC); diff --git a/examples/roulette.rs b/examples/roulette.rs index 2666dd2..1d090a2 100644 --- a/examples/roulette.rs +++ b/examples/roulette.rs @@ -11,7 +11,7 @@ extern crate cortex_m_rtfm as rtfm; use cast::{usize, u8}; use cortex_m::peripheral::SystClkSource; -use f4::led::{self, LEDS}; +use f4::leds::{LEDS}; use rtfm::{app, Threshold}; // CONFIGURATION @@ -35,7 +35,7 @@ app! { // INITIALIZATION PHASE fn init(p: init::Peripherals, _r: init::Resources) { - led::init(p.GPIOB, p.RCC); + f4::leds::init(p.GPIOB, p.RCC); p.SYST.set_clock_source(SystClkSource::Core); p.SYST.set_reload(16_000_000 / DIVISOR); diff --git a/src/dma.rs b/src/dma.rs index 3fecd54..443f41c 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -19,13 +19,18 @@ pub enum Error { Transfer, } +/// Channel 1 of DMA1 +pub struct Dma1Channel1 { + _0: (), +} + /// Channel 2 of DMA1 pub struct Dma1Channel2 { _0: (), } -/// Channel 6 of DMA1 -pub struct Dma1Channel6 { +/// Channel 4 of DMA1 +pub struct Dma1Channel4 { _0: (), } @@ -34,6 +39,11 @@ pub struct Dma1Channel5 { _0: (), } +/// Channel 6 of DMA1 +pub struct Dma1Channel6 { + _0: (), +} + /// Buffer to be used with a certain DMA `CHANNEL` // NOTE(packed) workaround for rust-lang/rust#41315 #[repr(packed)] @@ -214,7 +224,7 @@ impl<T> Buffer<T, Dma1Channel2> { } } -impl<T> Buffer<T, Dma1Channel6> { +impl<T> Buffer<T, Dma1Channel4> { /// Waits until the DMA releases this buffer pub fn release(&self, dma1: &DMA1) -> nb::Result<(), Error> { let state = self.state.get(); @@ -223,12 +233,12 @@ impl<T> Buffer<T, Dma1Channel6> { return Ok(()); } - if dma1.hisr.read().teif6().bit_is_set() { + if dma1.hisr.read().teif4().bit_is_set() { Err(nb::Error::Other(Error::Transfer)) - } else if dma1.hisr.read().tcif6().bit_is_set() { + } else if dma1.hisr.read().tcif4().bit_is_set() { unsafe { self.unlock(state) } - dma1.hifcr.write(|w| w.ctcif6().set_bit()); - dma1.s6cr.modify(|_, w| w.en().clear_bit()); + dma1.hifcr.write(|w| w.ctcif4().set_bit()); + dma1.s2cr.modify(|_, w| w.en().clear_bit()); Ok(()) } else { Err(nb::Error::WouldBlock) @@ -250,10 +260,125 @@ impl<T> Buffer<T, Dma1Channel5> { } else if dma1.hisr.read().tcif5().bit_is_set() { unsafe { self.unlock(state) } dma1.hifcr.write(|w| w.ctcif5().set_bit()); - dma1.s5cr.modify(|_, w| w.en().clear_bit()); + dma1.s2cr.modify(|_, w| w.en().clear_bit()); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } +} + +impl<T> Buffer<T, Dma1Channel6> { + /// Waits until the DMA releases this buffer + pub fn release(&self, dma1: &DMA1) -> nb::Result<(), Error> { + let state = self.state.get(); + + if state == State::Unlocked { + return Ok(()); + } + + if dma1.hisr.read().teif6().bit_is_set() { + Err(nb::Error::Other(Error::Transfer)) + } else if dma1.hisr.read().tcif6().bit_is_set() { + unsafe { self.unlock(state) } + dma1.hifcr.write(|w| w.ctcif6().set_bit()); + dma1.s2cr.modify(|_, w| w.en().clear_bit()); Ok(()) } else { Err(nb::Error::WouldBlock) } } } + +/// A circular buffer associated to a DMA `CHANNEL` +pub struct CircBuffer<B, CHANNEL> { + _marker: PhantomData<CHANNEL>, + buffer: UnsafeCell<[B; 2]>, + state: Cell<CircState>, +} + +impl<B, CHANNEL> CircBuffer<B, CHANNEL> { + pub(crate) fn lock(&self) -> &[B; 2] { + assert_eq!(self.state.get(), CircState::Free); + + self.state.set(CircState::MutatingFirstHalf); + + unsafe { &*self.buffer.get() } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum CircState { + /// Not in use by the DMA + Free, + /// The DMA is mutating the first half of the buffer + MutatingFirstHalf, + /// The DMA is mutating the second half of the buffer + MutatingSecondHalf, +} + +impl<B> CircBuffer<B, Dma1Channel1> { + /// Constructs a circular buffer from two halves + pub const fn new(buffer: [B; 2]) -> Self { + CircBuffer { + _marker: PhantomData, + buffer: UnsafeCell::new(buffer), + state: Cell::new(CircState::Free), + } + } + + /// Yields read access to the half of the circular buffer that's not + /// currently being mutated by the DMA + pub fn read<R, F>(&self, dma1: &DMA1, f: F) -> nb::Result<R, Error> + where + F: FnOnce(&B) -> R, + { + let state = self.state.get(); + + assert_ne!(state, CircState::Free); + + let isr = dma1.lisr.read(); + + if isr.teif1().bit_is_set() { + Err(nb::Error::Other(Error::Transfer)) + } else { + match state { + CircState::MutatingFirstHalf => if isr.tcif1().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else if isr.htif1().bit_is_set() { + dma1.lifcr.write(|w| w.chtif1().set_bit()); + + self.state.set(CircState::MutatingSecondHalf); + + let ret = f(unsafe { &(*self.buffer.get())[0] }); + + if isr.tcif1().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else { + Ok(ret) + } + } else { + Err(nb::Error::WouldBlock) + }, + CircState::MutatingSecondHalf => if isr.htif1().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else if isr.tcif1().bit_is_set() { + dma1.lifcr.write(|w| w.ctcif1().set_bit()); + + self.state.set(CircState::MutatingFirstHalf); + + let ret = f(unsafe { &(*self.buffer.get())[1] }); + + if isr.htif1().bit_is_set() { + Err(nb::Error::Other(Error::Overrun)) + } else { + Ok(ret) + } + } else { + Err(nb::Error::WouldBlock) + }, + _ => unreachable!(), + } + } + } +} \ No newline at end of file diff --git a/src/leds.rs b/src/leds.rs new file mode 100644 index 0000000..bf814c4 --- /dev/null +++ b/src/leds.rs @@ -0,0 +1,57 @@ +//! Eight LEDs connected to PORTB + +use stm32f40x::{GPIOB, RCC}; + +/// All the LEDs +pub static LEDS: [Led; 8] = [ + Led { i: 2 }, + Led { i: 1 }, + Led { i: 15 }, + Led { i: 14 }, + Led { i: 13 }, + Led { i: 5 }, + Led { i: 4 }, + Led { i: 10 }, +]; + +/// An LED +pub struct Led { + i: u8, +} + +impl Led { + /// Turns off the LED + pub fn off(&self) { + // NOTE(safe) atomic write + unsafe { (*GPIOB.get()).bsrr.write(|w| w.bits(1 << (self.i + 16))) } + } + + /// Turns on the LED + pub fn on(&self) { + // NOTE(safe) atomic write + unsafe { (*GPIOB.get()).bsrr.write(|w| w.bits(1 << self.i)) } + } +} + +/// Initializes all the user LEDs +pub fn init(gpioa: &GPIOB, rcc: &RCC) { + // Power up peripherals + rcc.ahb1enr.modify(|_, w| w.gpioben().set_bit()); + + // Configure pins 8-15 as outputs + gpioa + .moder + .modify( + |_, w| {unsafe { + w.moder2().bits(1) + .moder1().bits(1) + .moder15().bits(1) + .moder14().bits(1) + .moder13().bits(1) + .moder5().bits(1) + .moder4().bits(1) + .moder10().bits(1) + } + }, + ); +} diff --git a/src/lib.rs b/src/lib.rs index 419783c..2d776ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ //! [examples]: ./examples/index.html #![deny(missing_docs)] -#![deny(warnings)] +// #![deny(warnings)] #![feature(const_fn)] #![feature(const_unsafe_cell_new)] #![feature(const_cell_new)] @@ -37,6 +37,7 @@ pub mod examples; pub mod dma; pub mod led; +pub mod leds; pub mod serial; pub mod timer; pub mod time; diff --git a/src/pwm.rs b/src/pwm.rs index a5e8e01..41362e4 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -31,20 +31,181 @@ //! - CH4 = PB9 use core::any::{Any, TypeId}; -// use core::marker::Unsize; +use core::marker::Unsize; use cast::{u16, u32}; use hal; -// use static_ref::Static; +use static_ref::Static; use stm32f40x::{DMA1, TIM1, TIM2, TIM3, TIM4, GPIOA, GPIOB, GPIOC, RCC}; -// use dma::{self, Buffer, Dma1Channel2}; +use dma::{self, Buffer, Dma1Channel2}; use timer::{Channel}; /// PWM driver pub struct Pwm<'a, T>(pub &'a T) where T: 'a; +impl<'a> Pwm<'a, TIM1> { + /// Initializes the PWM module + pub fn init<P>(&self, + period: P, + dma1: Option<&DMA1>, + gpioa: &GPIOA, + gpiob: &GPIOB, + gpioc: &GPIOC, + rcc: &RCC + ) where + P: Into<::apb2::Ticks>, + { + self._init(period.into(), dma1, gpioa, gpiob, gpioc, rcc) + } + + fn _init( + &self, + period: ::apb2::Ticks, + dma1: Option<&DMA1>, + gpioa: &GPIOA, + gpiob: &GPIOB, + gpioc: &GPIOC, + rcc: &RCC, + ) { + let tim1 = self.0; + + rcc.apb2enr.modify(|_, w| w.tim1en().set_bit()); + rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + // CH1 = PA8 = alternate push-pull + // CH2 = PA9 = alternate push-pull + // CH3 = PA10 = alternate push-pull + // CH4 = PA11 = alternate push-pull + gpioa.afrh.modify(|_, w| { + w.afrh8().bits(1) + .afrh9().bits(1) + .afrh10().bits(1) + .afrh11().bits(1) + }); + gpioa.moder.modify(|_, w| { + w.moder8().bits(2) + .moder9().bits(2) + .moder10().bits(2) + .moder11().bits(2) + }); + + // PWM mode 1 + tim1.ccmr1_output.modify(|_, w| unsafe{ + w.oc1pe() + .set_bit() + .oc1m() + .bits(0b110) + .oc2pe() + .set_bit() + .oc2m() + .bits(0b110) + }); + tim1.ccmr2_output.modify(|_, w| unsafe{ + w.oc3pe() + .set_bit() + .oc3m() + .bits(0b110) + .oc4pe() + .set_bit() + .oc4m() + .bits(0b110) + }); + tim1.ccer.modify(|_, w| { + w.cc1p() + .clear_bit() + .cc2p() + .clear_bit() + .cc3p() + .clear_bit() + .cc4p() + .clear_bit() + }); + + tim1.bdtr.modify(|_, w| w.moe().set_bit()); + + self._set_period(period); + + tim1.cr1.write(|w| unsafe { + w.cms() + .bits(0b00) + .dir() + .bit(false) + .opm() + .bit(false) + .cen() + .set_bit() + }); + } + + fn _set_period(&self, period: ::apb2::Ticks) { + let period = period.0; + + let psc = u16((period - 1) / (1 << 16)).unwrap(); + self.0.psc.write(|w| unsafe{w.psc().bits(psc)}); + + let arr = u16(period / u32(psc + 1)).unwrap(); + self.0.arr.write(|w| unsafe{w.arr().bits(arr)}); + } +} + +impl<'a> hal::Pwm for Pwm<'a, TIM1> { + type Channel = Channel; + type Time = ::apb2::Ticks; + type Duty = u16; + + fn disable(&self, channel: Channel) { + match channel { + Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().clear_bit()), + Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().clear_bit()), + Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().clear_bit()), + Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().clear_bit()), + } + } + + fn enable(&self, channel: Channel) { + match channel { + Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().set_bit()), + Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().set_bit()), + Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().set_bit()), + Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().set_bit()), + } + } + + fn get_duty(&self, channel: Channel) -> u16 { + match channel { + Channel::_1 => self.0.ccr1.read().ccr1().bits(), + Channel::_2 => self.0.ccr2.read().ccr2().bits(), + Channel::_3 => self.0.ccr3.read().ccr3().bits(), + Channel::_4 => self.0.ccr4.read().ccr4().bits(), + } + } + + fn get_max_duty(&self) -> u16 { + self.0.arr.read().arr().bits() + } + + fn get_period(&self) -> ::apb2::Ticks { + ::apb2::Ticks(u32(self.0.psc.read().bits() * self.0.arr.read().bits())) + } + + fn set_duty(&self, channel: Channel, duty: u16) { + match channel { + Channel::_1 => self.0.ccr1.write(|w| unsafe{w.ccr1().bits(duty)}), + Channel::_2 => self.0.ccr2.write(|w| unsafe{w.ccr2().bits(duty)}), + Channel::_3 => self.0.ccr3.write(|w| unsafe{w.ccr3().bits(duty)}), + Channel::_4 => self.0.ccr4.write(|w| unsafe{w.ccr4().bits(duty)}), + } + } + + fn set_period<P>(&self, period: P) + where + P: Into<::apb2::Ticks>, + { + self._set_period(period.into()) + } +} macro_rules! impl_Pwm { ($TIM:ident, $APB:ident) => { @@ -190,6 +351,7 @@ macro_rules! impl_Pwm { // PWM mode 1 if tim.get_type_id() == TypeId::of::<TIM2>() { + // Ignore conflicting pin for channel 4 tim.ccmr1_output.modify(|_, w| unsafe { w.oc1pe() .set_bit() @@ -245,47 +407,45 @@ macro_rules! impl_Pwm { self._set_period(period); - // if let Some(dma1) = dma1 { - // tim2.dier.modify(|_, w| w.ude().set_bit()); - - // if tim2.get_type_id() == TypeId::of::<TIM2>() { - // // TIM2_UP - // // mem2mem: Memory to memory mode disabled - // // pl: Medium priority - // // msize: Memory size = 8 bits - // // psize: Peripheral size = 16 bits - // // minc: Memory increment mode enabled - // // pinc: Peripheral increment mode disabled - // // circ: Circular mode disabled - // // dir: Transfer from memory to peripheral - // // tceie: Transfer complete interrupt enabled - // // en: Disabled - // dma1.ccr2.write(|w| unsafe { - // w.mem2mem() - // .clear_bit() - // .pl() - // .bits(0b01) - // .msize() - // .bits(0b00) - // .psize() - // .bits(0b01) - // .minc() - // .set_bit() - // .pinc() - // .clear_bit() - // .circ() - // .clear_bit() - // .dir() - // .set_bit() - // .tcie() - // .set_bit() - // .en() - // .clear_bit() - // }); - // } else { - // unimplemented!() - // } - // } + if let Some(dma1) = dma1 { + tim.dier.modify(|_, w| w.ude().set_bit()); + + if tim.get_type_id() == TypeId::of::<TIM3>() { + // TIM3_CH4/UP + // mem2mem: Memory to memory mode disabled + // pl: Medium priority + // msize: Memory size = 8 bits + // psize: Peripheral size = 16 bits + // minc: Memory increment mode enabled + // pinc: Peripheral increment mode disabled + // circ: Circular mode disabled + // dir: Transfer from memory to peripheral + // tceie: Transfer complete interrupt enabled + // en: Disabled + dma1.s2cr.write(|w| unsafe { + w.pl() + .bits(0b01) + .msize() + .bits(0b00) + .psize() + .bits(0b01) + .minc() + .set_bit() + .pinc() + .clear_bit() + .circ() + .clear_bit() + .dir() + .bits(0) + .tcie() + .set_bit() + .en() + .clear_bit() + }); + } else { + unimplemented!() + } + } tim.cr1.write(|w| unsafe { w.cms() @@ -309,45 +469,45 @@ macro_rules! impl_Pwm { self.0.arr.write(|w| unsafe{w.bits(arr)}); } - // /// Uses `buffer` to continuously change the duty cycle on every period - // pub fn set_duties<B>( - // &self, - // dma1: &DMA1, - // channel: Channel, - // buffer: &Static<Buffer<B, Dma1Channel2>>, - // ) -> ::core::result::Result<(), dma::Error> - // where - // B: Unsize<[u8]>, - // { - // let tim2 = self.0; - - // if tim2.get_type_id() == TypeId::of::<TIM2>() { - // if dma1.ccr2.read().en().bit_is_set() { - // return Err(dma::Error::InUse); - // } - - // let buffer: &[u8] = buffer.lock(); - - // dma1.cndtr2 - // .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) }); - // dma1.cpar2.write(|w| unsafe { - // match channel { - // Channel::_1 => w.bits(&tim2.ccr1 as *const _ as u32), - // Channel::_2 => w.bits(&tim2.ccr2 as *const _ as u32), - // Channel::_3 => w.bits(&tim2.ccr3 as *const _ as u32), - // Channel::_4 => w.bits(&tim2.ccr4 as *const _ as u32), - // } - // }); - // dma1.cmar2 - // .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); - // dma1.ccr2.modify(|_, w| w.en().set_bit()); - - // Ok(()) - - // } else { - // unimplemented!() - // } - // } + /// Uses `buffer` to continuously change the duty cycle on every period + pub fn set_duties<B>( + &self, + dma1: &DMA1, + channel: Channel, + buffer: &Static<Buffer<B, Dma1Channel2>>, + ) -> ::core::result::Result<(), dma::Error> + where + B: Unsize<[u8]>, + { + let tim3 = self.0; + + if tim3.get_type_id() == TypeId::of::<TIM3>() { + if dma1.s2cr.read().en().bit_is_set() { + return Err(dma::Error::InUse); + } + + let buffer: &[u8] = buffer.lock(); + + dma1.s2ndtr + .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) }); + dma1.s2par.write(|w| unsafe { + match channel { + Channel::_1 => w.bits(&tim3.ccr1 as *const _ as u32), + Channel::_2 => w.bits(&tim3.ccr2 as *const _ as u32), + Channel::_3 => w.bits(&tim3.ccr3 as *const _ as u32), + Channel::_4 => w.bits(&tim3.ccr4 as *const _ as u32), + } + }); + dma1.s2m0ar + .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); + dma1.s2cr.modify(|_, w| w.en().set_bit()); + + Ok(()) + + } else { + unimplemented!() + } + } } impl<'a> hal::Pwm for Pwm<'a, $TIM> @@ -357,21 +517,12 @@ macro_rules! impl_Pwm { type Time = ::$APB::Ticks; fn get_duty(&self, channel: Channel) -> u32 { - // if self.0.get_type_id() == TypeId::of::<TIM1>() { - // match channel { - // Channel::_1 => u32(u32(self.0.ccr1.read().bits()), - // Channel::_2 => u32(u32(self.0.ccr2.read().bits()), - // Channel::_3 => u32(u32(self.0.ccr3.read().bits()), - // Channel::_4 => u32(u32(self.0.ccr4.read().bits()), - // } - // } else { - match channel { - Channel::_1 => u32(self.0.ccr1.read().ccr1_h().bits()) << 16 | u32(self.0.ccr1.read().ccr1_l().bits()), - Channel::_2 => u32(self.0.ccr2.read().ccr2_h().bits()) << 16 | u32(self.0.ccr2.read().ccr2_l().bits()), - Channel::_3 => u32(self.0.ccr3.read().ccr3_h().bits()) << 16 | u32(self.0.ccr3.read().ccr3_l().bits()), - Channel::_4 => u32(self.0.ccr4.read().ccr4_h().bits()) << 16 | u32(self.0.ccr4.read().ccr4_l().bits()), - } - // } + match channel { + Channel::_1 => u32(self.0.ccr1.read().ccr1_h().bits()) << 16 | u32(self.0.ccr1.read().ccr1_l().bits()), + Channel::_2 => u32(self.0.ccr2.read().ccr2_h().bits()) << 16 | u32(self.0.ccr2.read().ccr2_l().bits()), + Channel::_3 => u32(self.0.ccr3.read().ccr3_h().bits()) << 16 | u32(self.0.ccr3.read().ccr3_l().bits()), + Channel::_4 => u32(self.0.ccr4.read().ccr4_h().bits()) << 16 | u32(self.0.ccr4.read().ccr4_l().bits()), + } } fn disable(&self, channel: Channel) { @@ -421,7 +572,6 @@ macro_rules! impl_Pwm { } } -// impl_Pwm!(TIM1,apb2); impl_Pwm!(TIM2,apb1); impl_Pwm!(TIM3,apb1); impl_Pwm!(TIM4,apb1); \ No newline at end of file -- GitLab