Skip to content

Commit

Permalink
Add initial ctimer pwm implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
david-sawatzke committed Jan 11, 2020
1 parent 92754d6 commit 7460f7d
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ required-features = ["rt-selected", "82x"]
name = "usart"
required-features = ["rt-selected"]

[[example]]
name = "ctimer_fade"
required-features = ["rt-selected", "845"]

[profile.dev]
debug = true

Expand Down
74 changes: 74 additions & 0 deletions examples/ctimer_fade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#![no_main]
#![no_std]

extern crate panic_halt;

use lpc8xx_hal::{cortex_m_rt::entry, delay::Delay, prelude::*, Peripherals};

#[entry]
fn main() -> ! {
// Get access to the device's peripherals. Since only one instance of this
// struct can exist, the call to `take` returns an `Option<Peripherals>`.
// If we tried to call the method a second time, it would return `None`, but
// we're only calling it the one time here, so we can safely `unwrap` the
// `Option` without causing a panic.
let p = Peripherals::take().unwrap();

// Initialize the APIs of the peripherals we need.
let swm = p.SWM.split();
let mut delay = Delay::new(p.SYST);
let mut syscon = p.SYSCON.split();

// TODO
// Wait until #183 is fixed
let mut handle = swm
.handle
.disable(&mut syscon.handle)
.enable(&mut syscon.handle);

// Use 8 bit pwm
let (red_pwm, green_pwm, blue_pwm) =
p.CTIMER0.start_pwm(256, 0, &mut syscon.handle);

// Select pin for the RGB LED
let green = swm.pins.pio1_0.into_swm_pin();
let blue = swm.pins.pio1_1.into_swm_pin();
let red = swm.pins.pio1_2.into_swm_pin();

// Configure the LED pins. The API tracks the state of pins at compile time,
// to prevent any mistakes.
let (red, _) = swm.movable_functions.t0_mat0.assign(red, &mut handle);
let (green, _) = swm.movable_functions.t0_mat1.assign(green, &mut handle);
let (blue, _) = swm.movable_functions.t0_mat2.assign(blue, &mut handle);

let mut red = red_pwm.configure(red);
let mut green = green_pwm.configure(green);
let mut blue = blue_pwm.configure(blue);
// Fade each color after anothe
loop {
for i in 0..red.get_max_duty() {
delay.delay_ms(4_u8);
red.set_duty(i);
}
for i in (0..red.get_max_duty()).rev() {
delay.delay_ms(4_u8);
red.set_duty(i);
}
for i in 0..green.get_max_duty() {
delay.delay_ms(4_u8);
green.set_duty(i);
}
for i in (0..green.get_max_duty()).rev() {
delay.delay_ms(4_u8);
green.set_duty(i);
}
for i in 0..blue.get_max_duty() {
delay.delay_ms(4_u8);
blue.set_duty(i);
}
for i in (0..blue.get_max_duty()).rev() {
delay.delay_ms(4_u8);
blue.set_duty(i);
}
}
}
149 changes: 149 additions & 0 deletions src/ctimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//! PwmPin implementation based on CTimer
//!
//!

// Use the timer as one 32 bit timer
// Don't implement prescaling, since it isn't needed
// Currently only implemented for lpc845
use crate::pac::CTIMER0;
use crate::swm::{self, PinTrait, T0_MAT0, T0_MAT1, T0_MAT2};
use crate::syscon::{self};
use core::marker::PhantomData;
use embedded_hal::PwmPin;

/// Interface to a CTimer peripheral
///
/// Controls the CTimer. Use [`Peripherals`] to gain access to an instance of
/// this struct.
///
/// Please refer to the [module documentation] for more information.
///
/// [`Peripherals`]: ../struct.Peripherals.html
/// [module documentation]: index.html
pub struct CTimer {
ct: CTIMER0,
}

/// An unconfigured PwmPin
pub struct UnconfiguredPwmPin<CTOutput> {
number: u8,
// TODO Do the specific registers properly
output: PhantomData<CTOutput>,
}

/// TODO
pub struct CTimerPwmPin {
number: u8,
}

impl CTimer {
pub(crate) fn new(ct: CTIMER0) -> Self {
Self { ct }
}

/// TODO
pub fn start_pwm(
self,
period: u32,
prescaler: u32,
syscon: &mut syscon::Handle,
) -> (
UnconfiguredPwmPin<T0_MAT0>,
UnconfiguredPwmPin<T0_MAT1>,
UnconfiguredPwmPin<T0_MAT2>,
) {
syscon.enable_clock(&self.ct);
unsafe { self.ct.pr.write(|w| w.prval().bits(prescaler)) };
// Use MAT3 to reset the counter
unsafe { self.ct.mr[3].write(|w| w.match_().bits(period)) };
self.ct.mcr.write(|w| {
w.mr3r().set_bit();
// Use shadow registers for the pwm output matches
w.mr0rl().set_bit();
w.mr1rl().set_bit();
w.mr2rl().set_bit()
});

self.ct.pwmc.write(|w| {
w.pwmen0().set_bit();
w.pwmen1().set_bit();
w.pwmen2().set_bit()
});

// Start the timer
self.ct.tcr.write(|w| w.cen().set_bit());
(
UnconfiguredPwmPin {
number: 0,
output: PhantomData {},
},
UnconfiguredPwmPin {
number: 1,
output: PhantomData {},
},
UnconfiguredPwmPin {
number: 2,
output: PhantomData {},
},
)
}

/// Return the raw peripheral
///
/// This method serves as an escape hatch from the HAL API. It returns the
/// raw peripheral, allowing you to do whatever you want with it, without
/// limitations imposed by the API.
///
/// If you are using this method because a feature you need is missing from
/// the HAL API, please [open an issue] or, if an issue for your feature
/// request already exists, comment on the existing issue, so we can
/// prioritize it accordingly.
///
/// [open an issue]: https://github.com/lpc-rs/lpc8xx-hal/issues
pub fn free(self) -> CTIMER0 {
self.ct
}
}

impl<CTOutput> UnconfiguredPwmPin<CTOutput> {
/// Assings a pin to an `UnconfiguredPwmOutput`,
/// allowing it to be used as a pwm output
pub fn configure<PWM>(
self,
_: swm::Function<CTOutput, swm::state::Assigned<PWM>>,
) -> CTimerPwmPin
where
PWM: PinTrait,
{
CTimerPwmPin {
number: self.number,
}
}
}

impl PwmPin for CTimerPwmPin {
type Duty = u32;
fn enable(&mut self) {
// TODO
}

fn disable(&mut self) {
// TODO
}

fn get_duty(&self) -> Self::Duty {
unsafe { &(*CTIMER0::ptr()).msr[self.number as usize] }
.read()
.match_shadow()
.bits()
}

fn get_max_duty(&self) -> Self::Duty {
unsafe { &(*CTIMER0::ptr()).mr[3] }.read().match_().bits()
}

fn set_duty(&mut self, duty: Self::Duty) {
let reg = unsafe { &(*CTIMER0::ptr()).msr[self.number as usize] };
unsafe { reg.write(|w| w.match_shadow().bits(duty)) };
}
}
20 changes: 10 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ pub extern crate nb;
pub(crate) mod reg_proxy;

pub mod clock;
#[cfg(feature = "845")]
pub mod ctimer;
pub mod delay;
pub mod dma;
pub mod gpio;
Expand Down Expand Up @@ -140,6 +142,8 @@ pub use lpc82x_pac as pac;
#[cfg(feature = "845")]
pub use lpc845_pac as pac;

#[cfg(feature = "845")]
pub use self::ctimer::CTimer;
pub use self::dma::DMA;
pub use self::gpio::GPIO;
#[cfg(feature = "82x")]
Expand Down Expand Up @@ -184,6 +188,10 @@ use embedded_hal as hal;
/// use of the hardware.
#[allow(non_snake_case)]
pub struct Peripherals {
/// Standard counter/timer (CTIMER)
#[cfg(feature = "845")]
pub CTIMER0: CTimer,

/// DMA controller
pub DMA: DMA,

Expand Down Expand Up @@ -266,14 +274,6 @@ pub struct Peripherals {
/// allow you full, unprotected access to the peripheral.
pub CRC: pac::CRC,

/// Standard counter/timer (CTIMER)
///
/// A HAL API for this peripheral has not been implemented yet. In the
/// meantime, this field provides you with the raw register mappings, which
/// allow you full, unprotected access to the peripheral.
#[cfg(feature = "845")]
pub CTIMER0: pac::CTIMER0,

/// Digital-to-Analog Converter 0 (DAC0)
///
/// A HAL API for this peripheral has not been implemented yet. In the
Expand Down Expand Up @@ -502,6 +502,8 @@ impl Peripherals {
fn new(p: pac::Peripherals, cp: pac::CorePeripherals) -> Self {
Peripherals {
// HAL peripherals
#[cfg(feature = "845")]
CTIMER0: CTimer::new(p.CTIMER0),
DMA: DMA::new(p.DMA0),
// NOTE(unsafe) The init state of the gpio peripheral is enabled,
// thus it's safe to create an already initialized gpio port
Expand Down Expand Up @@ -530,8 +532,6 @@ impl Peripherals {
CAPT: p.CAPT,
CRC: p.CRC,
#[cfg(feature = "845")]
CTIMER0: p.CTIMER0,
#[cfg(feature = "845")]
DAC0: p.DAC0,
#[cfg(feature = "845")]
DAC1: p.DAC1,
Expand Down
4 changes: 4 additions & 0 deletions src/syscon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ impl_clock_control!(pac::SWM0, swm);
impl_clock_control!(pac::SCT0, sct);
impl_clock_control!(pac::WKT, wkt);
impl_clock_control!(pac::MRT0, mrt);
#[cfg(feature = "845")]
impl_clock_control!(pac::CTIMER0, ctimer);
impl_clock_control!(pac::SPI0, spi0);
impl_clock_control!(pac::SPI1, spi1);
impl_clock_control!(pac::CRC, crc);
Expand Down Expand Up @@ -529,6 +531,8 @@ impl_reset_control!(pac::I2C0, i2c0_rst_n);
impl_reset_control!(pac::MRT0, mrt_rst_n);
impl_reset_control!(pac::SCT0, sct_rst_n);
impl_reset_control!(pac::WKT, wkt_rst_n);
#[cfg(feature = "845")]
impl_reset_control!(pac::CTIMER0, ctimer_rst_n);
#[cfg(feature = "82x")]
impl_reset_control!(pac::GPIO, gpio_rst_n);
impl_reset_control!(pac::FLASH_CTRL, flash_rst_n);
Expand Down

0 comments on commit 7460f7d

Please sign in to comment.