#![allow(dead_code)]
mod consts;
mod instances;
pub use consts::{
PwmChannel, PwmClockSource, PwmError, PwmMode, PwmPolarity, PwmRegisters,
PWM_DEFAULT_CLK_FREQ, PWM_MAX_PERIOD, PWM_MAX_PULSE_COUNT, PWM_MAX_SHIFT_COUNT,
};
pub use instances::{
pwm_controller_base, GlobalPwmChannel, PWM0_BASE, PWM1_BASE, PWM2_BASE, PWM3_BASE,
};
use consts::*;
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
pub struct Pwm {
regs: &'static PwmRegisters,
clock_source: PwmClockSource,
}
impl Pwm {
pub unsafe fn new(base: usize) -> Self {
unsafe {
Self {
regs: &*(base as *const PwmRegisters),
clock_source: PwmClockSource::Clk100MHz,
}
}
}
pub fn set_clock_source(&mut self, source: PwmClockSource) {
self.clock_source = source;
}
pub fn clock_source(&self) -> PwmClockSource {
self.clock_source
}
pub fn clock_frequency(&self) -> u32 {
self.clock_source.frequency()
}
pub fn configure_channel(
&mut self,
channel: PwmChannel,
frequency_hz: u32,
duty_percent: u8,
polarity: PwmPolarity,
) -> Result<(), PwmError> {
if frequency_hz == 0 {
return Err(PwmError::InvalidPeriod);
}
if duty_percent > 100 {
return Err(PwmError::InvalidDutyCycle);
}
let period = self.clock_frequency() / frequency_hz;
if !(2..=PWM_MAX_PERIOD).contains(&period) {
return Err(PwmError::InvalidPeriod);
}
let hlperiod = (period as u64 * duty_percent as u64 / 100) as u32;
self.set_period_raw(channel, period);
self.set_hlperiod_raw(channel, hlperiod);
self.set_polarity(channel, polarity);
Ok(())
}
pub fn configure_channel_raw(
&mut self,
channel: PwmChannel,
period: u32,
hlperiod: u32,
polarity: PwmPolarity,
) -> Result<(), PwmError> {
if !(2..=PWM_MAX_PERIOD).contains(&period) {
return Err(PwmError::InvalidPeriod);
}
if hlperiod >= period {
return Err(PwmError::InvalidDutyCycle);
}
self.set_period_raw(channel, period);
self.set_hlperiod_raw(channel, hlperiod);
self.set_polarity(channel, polarity);
Ok(())
}
fn set_period_raw(&self, channel: PwmChannel, period: u32) {
match channel {
PwmChannel::Channel0 => self.regs.period0.write(PERIOD::PERIOD.val(period)),
PwmChannel::Channel1 => self.regs.period1.write(PERIOD::PERIOD.val(period)),
PwmChannel::Channel2 => self.regs.period2.write(PERIOD::PERIOD.val(period)),
PwmChannel::Channel3 => self.regs.period3.write(PERIOD::PERIOD.val(period)),
}
}
pub fn get_period_raw(&self, channel: PwmChannel) -> u32 {
match channel {
PwmChannel::Channel0 => self.regs.period0.read(PERIOD::PERIOD),
PwmChannel::Channel1 => self.regs.period1.read(PERIOD::PERIOD),
PwmChannel::Channel2 => self.regs.period2.read(PERIOD::PERIOD),
PwmChannel::Channel3 => self.regs.period3.read(PERIOD::PERIOD),
}
}
fn set_hlperiod_raw(&self, channel: PwmChannel, hlperiod: u32) {
match channel {
PwmChannel::Channel0 => self.regs.hlperiod0.write(HLPERIOD::HLPERIOD.val(hlperiod)),
PwmChannel::Channel1 => self.regs.hlperiod1.write(HLPERIOD::HLPERIOD.val(hlperiod)),
PwmChannel::Channel2 => self.regs.hlperiod2.write(HLPERIOD::HLPERIOD.val(hlperiod)),
PwmChannel::Channel3 => self.regs.hlperiod3.write(HLPERIOD::HLPERIOD.val(hlperiod)),
}
}
pub fn get_hlperiod_raw(&self, channel: PwmChannel) -> u32 {
match channel {
PwmChannel::Channel0 => self.regs.hlperiod0.read(HLPERIOD::HLPERIOD),
PwmChannel::Channel1 => self.regs.hlperiod1.read(HLPERIOD::HLPERIOD),
PwmChannel::Channel2 => self.regs.hlperiod2.read(HLPERIOD::HLPERIOD),
PwmChannel::Channel3 => self.regs.hlperiod3.read(HLPERIOD::HLPERIOD),
}
}
pub fn set_polarity(&self, channel: PwmChannel, polarity: PwmPolarity) {
let mask = channel.mask();
let current = self.regs.polarity.read(POLARITY::POLARITY);
let new_val = match polarity {
PwmPolarity::ActiveHigh => current & !mask,
PwmPolarity::ActiveLow => current | mask,
};
self.regs.polarity.modify(POLARITY::POLARITY.val(new_val));
}
pub fn get_polarity(&self, channel: PwmChannel) -> PwmPolarity {
let current = self.regs.polarity.read(POLARITY::POLARITY);
if current & channel.mask() != 0 {
PwmPolarity::ActiveLow
} else {
PwmPolarity::ActiveHigh
}
}
pub fn set_mode(&self, channel: PwmChannel, mode: PwmMode) {
let mask = channel.mask();
let current = self.regs.polarity.read(POLARITY::PWMMODE);
let new_val = match mode {
PwmMode::Continuous => current & !mask,
PwmMode::PulseCount => current | mask,
};
self.regs.polarity.modify(POLARITY::PWMMODE.val(new_val));
}
pub fn get_mode(&self, channel: PwmChannel) -> PwmMode {
let current = self.regs.polarity.read(POLARITY::PWMMODE);
if current & channel.mask() != 0 {
PwmMode::PulseCount
} else {
PwmMode::Continuous
}
}
pub fn set_pulse_count(&self, channel: PwmChannel, count: u32) -> Result<(), PwmError> {
if count == 0 || count > PWM_MAX_PULSE_COUNT {
return Err(PwmError::InvalidPulseCount);
}
match channel {
PwmChannel::Channel0 => self.regs.pcount0.write(PCOUNT::PCOUNT.val(count)),
PwmChannel::Channel1 => self.regs.pcount1.write(PCOUNT::PCOUNT.val(count)),
PwmChannel::Channel2 => self.regs.pcount2.write(PCOUNT::PCOUNT.val(count)),
PwmChannel::Channel3 => self.regs.pcount3.write(PCOUNT::PCOUNT.val(count)),
}
Ok(())
}
pub fn get_pulse_count(&self, channel: PwmChannel) -> u32 {
match channel {
PwmChannel::Channel0 => self.regs.pulsecount0.read(PULSECOUNT::PULSECOUNT),
PwmChannel::Channel1 => self.regs.pulsecount1.read(PULSECOUNT::PULSECOUNT),
PwmChannel::Channel2 => self.regs.pulsecount2.read(PULSECOUNT::PULSECOUNT),
PwmChannel::Channel3 => self.regs.pulsecount3.read(PULSECOUNT::PULSECOUNT),
}
}
pub fn start(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwmstart.read(PWMSTART::PWMSTART);
self.regs
.pwmstart
.write(PWMSTART::PWMSTART.val(current | mask));
}
pub fn stop(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwmstart.read(PWMSTART::PWMSTART);
self.regs
.pwmstart
.write(PWMSTART::PWMSTART.val(current & !mask));
}
pub fn restart(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwmupdate.read(PWMUPDATE::PWMUPDATE);
self.regs
.pwmupdate
.write(PWMUPDATE::PWMUPDATE.val(current | mask));
self.regs
.pwmupdate
.write(PWMUPDATE::PWMUPDATE.val(current));
}
pub fn is_running(&self, channel: PwmChannel) -> bool {
let current = self.regs.pwmstart.read(PWMSTART::PWMSTART);
current & channel.mask() != 0
}
pub fn is_done(&self, channel: PwmChannel) -> bool {
let done = self.regs.pwmdone.read(PWMDONE::PWMDONE);
done & channel.mask() != 0
}
pub fn enable_output(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwm_oe.read(PWM_OE::PWM_OE);
self.regs.pwm_oe.write(PWM_OE::PWM_OE.val(current | mask));
}
pub fn disable_output(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwm_oe.read(PWM_OE::PWM_OE);
self.regs.pwm_oe.write(PWM_OE::PWM_OE.val(current & !mask));
}
pub fn is_output_enabled(&self, channel: PwmChannel) -> bool {
let current = self.regs.pwm_oe.read(PWM_OE::PWM_OE);
current & channel.mask() != 0
}
pub fn update(&self, channel: PwmChannel) {
let mask = channel.mask();
let current = self.regs.pwmupdate.get();
self.regs.pwmupdate.set(current | mask);
self.regs.pwmupdate.set(current & !mask);
}
pub fn update_frequency_duty(
&mut self,
channel: PwmChannel,
frequency_hz: u32,
duty_percent: u8,
) -> Result<(), PwmError> {
if frequency_hz == 0 {
return Err(PwmError::InvalidPeriod);
}
if duty_percent > 100 {
return Err(PwmError::InvalidDutyCycle);
}
let period = self.clock_frequency() / frequency_hz;
if !(2..=PWM_MAX_PERIOD).contains(&period) {
return Err(PwmError::InvalidPeriod);
}
let hlperiod = (period as u64 * duty_percent as u64 / 100) as u32;
self.set_period_raw(channel, period);
self.set_hlperiod_raw(channel, hlperiod);
self.update(channel);
Ok(())
}
pub fn enable_shift_mode(&self) {
self.regs.polarity.modify(POLARITY::SHIFTMODE::SET);
}
pub fn disable_shift_mode(&self) {
self.regs.polarity.modify(POLARITY::SHIFTMODE::CLEAR);
}
pub fn is_shift_mode_enabled(&self) -> bool {
self.regs.polarity.is_set(POLARITY::SHIFTMODE)
}
pub fn configure_shift_mode(
&self,
shift0: u32,
shift1: u32,
shift2: u32,
shift3: u32,
) -> Result<(), PwmError> {
if shift0 > PWM_MAX_SHIFT_COUNT
|| shift1 > PWM_MAX_SHIFT_COUNT
|| shift2 > PWM_MAX_SHIFT_COUNT
|| shift3 > PWM_MAX_SHIFT_COUNT
{
return Err(PwmError::ConfigError);
}
self.regs.shiftcount0.write(SHIFTCOUNT::SHIFTCOUNT.val(shift0));
self.regs.shiftcount1.write(SHIFTCOUNT::SHIFTCOUNT.val(shift1));
self.regs.shiftcount2.write(SHIFTCOUNT::SHIFTCOUNT.val(shift2));
self.regs.shiftcount3.write(SHIFTCOUNT::SHIFTCOUNT.val(shift3));
self.enable_shift_mode();
Ok(())
}
pub fn set_shift_count(&self, channel: PwmChannel, shift: u32) -> Result<(), PwmError> {
if shift > PWM_MAX_SHIFT_COUNT {
return Err(PwmError::ConfigError);
}
match channel {
PwmChannel::Channel0 => self.regs.shiftcount0.write(SHIFTCOUNT::SHIFTCOUNT.val(shift)),
PwmChannel::Channel1 => self.regs.shiftcount1.write(SHIFTCOUNT::SHIFTCOUNT.val(shift)),
PwmChannel::Channel2 => self.regs.shiftcount2.write(SHIFTCOUNT::SHIFTCOUNT.val(shift)),
PwmChannel::Channel3 => self.regs.shiftcount3.write(SHIFTCOUNT::SHIFTCOUNT.val(shift)),
}
Ok(())
}
pub fn get_shift_count(&self, channel: PwmChannel) -> u32 {
match channel {
PwmChannel::Channel0 => self.regs.shiftcount0.read(SHIFTCOUNT::SHIFTCOUNT),
PwmChannel::Channel1 => self.regs.shiftcount1.read(SHIFTCOUNT::SHIFTCOUNT),
PwmChannel::Channel2 => self.regs.shiftcount2.read(SHIFTCOUNT::SHIFTCOUNT),
PwmChannel::Channel3 => self.regs.shiftcount3.read(SHIFTCOUNT::SHIFTCOUNT),
}
}
pub fn start_shift_mode(&self) {
self.regs.shiftstart.write(SHIFTSTART::SHIFTSTART::SET);
}
pub fn stop_shift_mode(&self) {
self.regs.shiftstart.write(SHIFTSTART::SHIFTSTART::CLEAR);
}
pub fn start_all(&self) {
self.regs.pwmstart.write(PWMSTART::PWMSTART.val(0xF));
}
pub fn stop_all(&self) {
self.regs.pwmstart.write(PWMSTART::PWMSTART.val(0));
}
pub fn enable_all_outputs(&self) {
self.regs.pwm_oe.write(PWM_OE::PWM_OE.val(0xF));
}
pub fn disable_all_outputs(&self) {
self.regs.pwm_oe.write(PWM_OE::PWM_OE.val(0));
}
pub fn force_pclk_on(&self) {
self.regs.polarity.modify(POLARITY::PCLK_FORCE_EN::SET);
}
pub fn enable_pclk_gating(&self) {
self.regs.polarity.modify(POLARITY::PCLK_FORCE_EN::CLEAR);
}
}