mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-22 01:16:20 +04:00
rust: make PWM usable with every timer
This commit is contained in:
parent
f8166abd0f
commit
62b594b8dc
@ -1,6 +1,6 @@
|
||||
use k210_hal::pac;
|
||||
// TODO: generalize over other timers than TIMER0
|
||||
// use pac::{timer0,TIMER0,TIMER1,TIMER2};
|
||||
use core::ops::Deref;
|
||||
use pac::{timer0,TIMER0,TIMER1,TIMER2};
|
||||
|
||||
use crate::soc::sysctl;
|
||||
|
||||
@ -12,17 +12,61 @@ pub enum Channel {
|
||||
CH4,
|
||||
}
|
||||
|
||||
pub trait TimerExt: Deref<Target = timer0::RegisterBlock> + Sized {
|
||||
#[doc(hidden)]
|
||||
const CLK: sysctl::clock;
|
||||
#[doc(hidden)]
|
||||
const DIV: sysctl::threshold;
|
||||
|
||||
/// Constrains TIMER peripheral for PWM use
|
||||
/// A timer channel can either be used for PWM or as a normal timer (say, for interrupt
|
||||
/// generation). Currently this has a larger granularity than needed and
|
||||
/// constrains the entire peripheral for PWM use.
|
||||
fn constrain_pwm(self) -> PWMImpl<Self>;
|
||||
}
|
||||
|
||||
impl TimerExt for TIMER0 {
|
||||
const CLK: sysctl::clock = sysctl::clock::TIMER0;
|
||||
const DIV: sysctl::threshold = sysctl::threshold::TIMER0;
|
||||
|
||||
fn constrain_pwm(self) -> PWMImpl<Self> { PWMImpl::<Self> { timer: self } }
|
||||
}
|
||||
impl TimerExt for TIMER1 {
|
||||
const CLK: sysctl::clock = sysctl::clock::TIMER1;
|
||||
const DIV: sysctl::threshold = sysctl::threshold::TIMER1;
|
||||
|
||||
fn constrain_pwm(self) -> PWMImpl<Self> { PWMImpl::<Self> { timer: self } }
|
||||
}
|
||||
impl TimerExt for TIMER2 {
|
||||
const CLK: sysctl::clock = sysctl::clock::TIMER2;
|
||||
const DIV: sysctl::threshold = sysctl::threshold::TIMER2;
|
||||
|
||||
fn constrain_pwm(self) -> PWMImpl<Self> { PWMImpl::<Self> { timer: self } }
|
||||
}
|
||||
|
||||
/** Trait for PWM control */
|
||||
pub trait PWM {
|
||||
// TODO: make this per channel, and use the PWM trait from Rust embedded
|
||||
fn start(&self, ch: Channel);
|
||||
fn stop(&self, ch: Channel);
|
||||
fn set(&self, ch: Channel, freq: u32, value: f32) -> u32;
|
||||
}
|
||||
|
||||
pub struct PWMImpl<TIMER> {
|
||||
timer: TIMER,
|
||||
}
|
||||
|
||||
impl<TIMER: TimerExt> PWM for PWMImpl<TIMER> {
|
||||
/** Start a PWM channel */
|
||||
pub fn pwm_start(ch: Channel) {
|
||||
fn start(&self, ch: Channel) {
|
||||
unsafe {
|
||||
let ptr = pac::TIMER0::ptr();
|
||||
use pac::timer0::channel::control::MODEW;
|
||||
|
||||
// set a deterministic value for load counts
|
||||
(*ptr).channel[ch as usize].load_count.write(|w| w.bits(1));
|
||||
(*ptr).load_count2[ch as usize].write(|w| w.bits(1));
|
||||
self.timer.channel[ch as usize].load_count.write(|w| w.bits(1));
|
||||
self.timer.load_count2[ch as usize].write(|w| w.bits(1));
|
||||
// start channel
|
||||
(*ptr).channel[ch as usize].control.write(
|
||||
self.timer.channel[ch as usize].control.write(
|
||||
|w| w.interrupt().set_bit()
|
||||
.pwm_enable().set_bit()
|
||||
.mode().variant(MODEW::USER)
|
||||
@ -31,26 +75,21 @@ pub fn pwm_start(ch: Channel) {
|
||||
}
|
||||
|
||||
/** Stop a PWM channel */
|
||||
pub fn pwm_stop(ch: Channel) {
|
||||
unsafe {
|
||||
let ptr = pac::TIMER0::ptr();
|
||||
|
||||
(*ptr).channel[ch as usize].control.write(
|
||||
fn stop(&self, ch: Channel) {
|
||||
self.timer.channel[ch as usize].control.write(
|
||||
|w| w.interrupt().set_bit());
|
||||
}
|
||||
}
|
||||
|
||||
/** Set frequency and value for a PWM channel */
|
||||
pub fn pwm_set(ch: Channel, freq: u32, value: f32) -> u32 {
|
||||
let clk_freq = sysctl::clock_get_freq(sysctl::clock::TIMER0);
|
||||
fn set(&self, ch: Channel, freq: u32, value: f32) -> u32 {
|
||||
let clk_freq = sysctl::clock_get_freq(TIMER::CLK);
|
||||
let periods = clk_freq / freq;
|
||||
let percent = (value * (periods as f32)) as u32;
|
||||
unsafe {
|
||||
let ptr = pac::TIMER0::ptr();
|
||||
(*ptr).channel[ch as usize].load_count.write(|w| w.bits(periods - percent));
|
||||
(*ptr).load_count2[ch as usize].write(|w| w.bits(percent));
|
||||
self.timer.channel[ch as usize].load_count.write(|w| w.bits(periods - percent));
|
||||
self.timer.load_count2[ch as usize].write(|w| w.bits(percent));
|
||||
}
|
||||
clk_freq / periods
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ use k210_shared::board::lcd_render::render_image;
|
||||
use k210_shared::board::ns2009::TouchScreen;
|
||||
use k210_shared::soc::fpioa;
|
||||
use k210_shared::soc::i2c::{I2CExt, I2C};
|
||||
use k210_shared::soc::pwm::{pwm_set, pwm_start, Channel};
|
||||
use k210_shared::soc::pwm::{TimerExt, PWM, Channel};
|
||||
use k210_shared::soc::sleep::usleep;
|
||||
use k210_shared::soc::spi::SPIExt;
|
||||
use k210_shared::soc::sysctl;
|
||||
@ -99,10 +99,11 @@ fn main() -> ! {
|
||||
});
|
||||
|
||||
writeln!(stdout, "start PWM").unwrap();
|
||||
let pwm = p.TIMER0.constrain_pwm();
|
||||
sysctl::clock_enable(sysctl::clock::TIMER0);
|
||||
pwm_start(Channel::CH1);
|
||||
pwm_start(Channel::CH2);
|
||||
pwm_start(Channel::CH3);
|
||||
pwm.start(Channel::CH1);
|
||||
pwm.start(Channel::CH2);
|
||||
pwm.start(Channel::CH3);
|
||||
|
||||
let freq = 10000;
|
||||
|
||||
@ -114,9 +115,9 @@ fn main() -> ! {
|
||||
//writeln!(stdout, "{:?}", ev).unwrap();
|
||||
let (r, g, b) = color_from_xy(x, y, clampf(ev.z as f32 / 1000.0));
|
||||
|
||||
pwm_set(Channel::CH1, freq, 1.0 - r * R_SCALE);
|
||||
pwm_set(Channel::CH2, freq, 1.0 - g * G_SCALE);
|
||||
pwm_set(Channel::CH3, freq, 1.0 - b * B_SCALE);
|
||||
pwm.set(Channel::CH1, freq, 1.0 - r * R_SCALE);
|
||||
pwm.set(Channel::CH2, freq, 1.0 - g * G_SCALE);
|
||||
pwm.set(Channel::CH3, freq, 1.0 - b * B_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user