Fix LEDC divider calculation, use REF_TICK when needed

This commit is contained in:
bjoernQ 2022-08-08 14:41:55 +02:00
parent 2a1ab6da0e
commit 275cede963
20 changed files with 113 additions and 134 deletions

View File

@ -137,7 +137,7 @@ where
#[cfg(feature = "esp32")]
/// Macro to configure channel parameters in hw
macro_rules! set_channel {
($self: ident, $speed: ident, $num: literal, $channel_number: ident) => {
($self: ident, $speed: ident, $num: literal, $timer_number: ident) => {
paste! {
$self.ledc.[<$speed sch $num _hpoint>]
.write(|w| unsafe { w.[<hpoint>]().bits(0x0) });
@ -145,7 +145,7 @@ macro_rules! set_channel {
w.[<sig_out_en>]()
.set_bit()
.[<timer_sel>]()
.bits($channel_number)
.bits($timer_number)
});
$self.ledc.[<$speed sch $num _conf1>].write(|w| unsafe {
w.[<duty_start>]()
@ -166,7 +166,7 @@ macro_rules! set_channel {
#[cfg(not(feature = "esp32"))]
/// Macro to configure channel parameters in hw
macro_rules! set_channel {
($self: ident, $speed: ident, $num: literal, $channel_number: ident) => {
($self: ident, $speed: ident, $num: literal, $timer_number: ident) => {
paste! {
$self.ledc.[<ch $num _hpoint>]
.write(|w| unsafe { w.[<hpoint>]().bits(0x0) });
@ -174,7 +174,7 @@ macro_rules! set_channel {
w.[<sig_out_en>]()
.set_bit()
.[<timer_sel>]()
.bits($channel_number)
.bits($timer_number)
});
$self.ledc.[<ch $num _conf1>].write(|w| unsafe {
w.[<duty_start>]()
@ -256,45 +256,45 @@ where
self.output_pin.set_to_push_pull_output();
let channel_number = timer.get_number() as u8;
let timer_number = timer.get_number() as u8;
match self.number {
Number::Channel0 => {
set_channel!(self, h, 0, channel_number);
set_channel!(self, h, 0, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG0);
}
Number::Channel1 => {
set_channel!(self, h, 1, channel_number);
set_channel!(self, h, 1, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG1);
}
Number::Channel2 => {
set_channel!(self, h, 2, channel_number);
set_channel!(self, h, 2, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG2);
}
Number::Channel3 => {
set_channel!(self, h, 3, channel_number);
set_channel!(self, h, 3, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG3);
}
Number::Channel4 => {
set_channel!(self, h, 4, channel_number);
set_channel!(self, h, 4, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG4);
}
Number::Channel5 => {
set_channel!(self, h, 5, channel_number);
set_channel!(self, h, 5, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG5);
}
Number::Channel6 => {
set_channel!(self, h, 6, channel_number);
set_channel!(self, h, 6, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG6);
}
Number::Channel7 => {
set_channel!(self, h, 7, channel_number);
set_channel!(self, h, 7, timer_number);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_HS_SIG7);
}
@ -335,54 +335,54 @@ where
self.output_pin.set_to_push_pull_output();
let channel_number = timer.get_number() as u8;
let timer_number = timer.get_number() as u8;
match self.number {
Number::Channel0 => {
set_channel!(self, l, 0, channel_number);
set_channel!(self, l, 0, timer_number);
update_channel!(self, 0);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG0);
}
Number::Channel1 => {
set_channel!(self, l, 1, channel_number);
set_channel!(self, l, 1, timer_number);
update_channel!(self, 1);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG1);
}
Number::Channel2 => {
set_channel!(self, l, 2, channel_number);
set_channel!(self, l, 2, timer_number);
update_channel!(self, 2);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG2);
}
Number::Channel3 => {
set_channel!(self, l, 3, channel_number);
set_channel!(self, l, 3, timer_number);
update_channel!(self, 3);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG3);
}
Number::Channel4 => {
set_channel!(self, l, 4, channel_number);
set_channel!(self, l, 4, timer_number);
update_channel!(self, 4);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG4);
}
Number::Channel5 => {
set_channel!(self, l, 5, channel_number);
set_channel!(self, l, 5, timer_number);
update_channel!(self, 5);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG5);
}
#[cfg(not(feature = "esp32c3"))]
Number::Channel6 => {
set_channel!(self, l, 6, channel_number);
set_channel!(self, l, 6, timer_number);
update_channel!(self, 6);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG6);
}
#[cfg(not(feature = "esp32c3"))]
Number::Channel7 => {
set_channel!(self, l, 7, channel_number);
set_channel!(self, l, 7, timer_number);
update_channel!(self, 7);
self.output_pin
.connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG7);

View File

@ -5,6 +5,8 @@ use super::HighSpeed;
use super::{LowSpeed, Speed};
use crate::{clock::Clocks, pac::ledc};
const LEDC_TIMER_DIV_NUM_MAX: u64 = 0x3FFFF;
/// Timer errors
#[derive(Debug)]
pub enum Error {
@ -133,6 +135,7 @@ pub struct Timer<'a, S: TimerSpeed> {
number: Number,
duty: Option<config::Duty>,
configured: bool,
use_ref_tick: bool,
clock_source: Option<S::ClockSourceType>,
}
@ -152,13 +155,18 @@ where
// TODO: we should return some error here if `unwrap()` fails
let src_freq: u32 = self.get_freq().unwrap().to_Hz();
let precision = 2u64.pow(config.duty as u32);
let precision = 1 << config.duty as u32;
let frequency: u32 = config.frequency.raw();
let divisor = (((src_freq as u64) << 8) + ((frequency as u64 * precision) / 2))
/ (frequency as u64 * precision);
let mut divisor = ((src_freq as u64) << 8) / frequency as u64 / precision as u64;
if divisor >= 0x10_0000 || divisor == 0 {
if divisor > LEDC_TIMER_DIV_NUM_MAX {
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
self.use_ref_tick = true;
divisor = ((1_000_000 as u64) << 8) / frequency as u64 / precision as u64;
}
if divisor >= LEDC_TIMER_DIV_NUM_MAX || divisor < 256 {
return Err(Error::Divisor);
}
@ -199,6 +207,7 @@ impl<'a, S: TimerSpeed> Timer<'a, S> {
number,
duty: None,
configured: false,
use_ref_tick: false,
clock_source: None,
}
}
@ -217,12 +226,12 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
/// Configure the HW for the timer
fn configure_hw(&self, divisor: u32) {
let duty = self.duty.unwrap() as u8;
let sel_lstimer = self.clock_source == Some(LSClockSource::APBClk);
let use_apb = !self.use_ref_tick;
match self.number {
Number::Timer0 => self.ledc.lstimer0_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_apb)
.rst()
.clear_bit()
.pause()
@ -234,7 +243,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer1 => self.ledc.lstimer1_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_apb)
.rst()
.clear_bit()
.pause()
@ -246,7 +255,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer2 => self.ledc.lstimer2_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_apb)
.rst()
.clear_bit()
.pause()
@ -258,7 +267,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer3 => self.ledc.lstimer3_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_apb)
.rst()
.clear_bit()
.pause()
@ -275,12 +284,12 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
/// Configure the HW for the timer
fn configure_hw(&self, divisor: u32) {
let duty = self.duty.unwrap() as u8;
let sel_lstimer = self.clock_source == Some(LSClockSource::APBClk);
let use_ref_tick = self.use_ref_tick;
match self.number {
Number::Timer0 => self.ledc.timer0_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
@ -292,7 +301,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer1 => self.ledc.timer1_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
@ -304,7 +313,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer2 => self.ledc.timer2_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
@ -316,7 +325,7 @@ impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
}),
Number::Timer3 => self.ledc.timer3_conf.modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_lstimer)
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()

View File

@ -52,11 +52,7 @@ fn main() -> ! {
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
pac::Interrupt::GPIO,
interrupt::Priority::Priority2,
)
.unwrap();
interrupt::enable(pac::Interrupt::GPIO, interrupt::Priority::Priority2).unwrap();
led.set_high().unwrap();

View File

@ -1,4 +1,5 @@
//! Turns on LED with the option to change LED intensity depending on `duty` value.
//! Turns on LED with the option to change LED intensity depending on `duty`
//! value.
//!
//! This assumes that a LED is connected to the pin assigned to `led`. (GPIO4)
@ -6,19 +7,21 @@
#![no_main]
use core::fmt::Write;
use esp32_hal::{
clock::ClockControl,
gpio::IO,
Serial,
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
HighSpeed,
LEDC,
},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
RtcCntl,
clock::ClockControl,
prelude::*,
pac::Peripherals,
};
use esp_hal_common::ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
HighSpeed, LEDC,
Serial,
};
use panic_halt as _;
use xtensa_lx_rt::entry;

View File

@ -11,11 +11,10 @@ use esp32_hal::{
clock::ClockControl,
pac::{Peripherals, TIMG1},
prelude::*,
timer::{Timer0, TimerGroup},
timer::{Timer, Timer0, TimerGroup},
CpuControl,
RtcCntl,
};
use esp_hal_common::Timer;
use esp_println::println;
use nb::block;
use panic_halt as _;
@ -24,10 +23,6 @@ use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
_main();
}
fn _main() -> ! {
let peripherals = Peripherals::take().unwrap();
let system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

View File

@ -10,13 +10,13 @@ use core::{cell::RefCell, fmt::Write};
use esp32_hal::{
clock::ClockControl,
interrupt,
interrupt::Priority,
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
timer::{Timer, Timer0, Timer1, TimerGroup},
RtcCntl,
Serial,
};
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;

View File

@ -91,4 +91,4 @@ fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
| ((nmi_enable as u8) << 1)
| (int_enable as u8) << 2
| ((nmi_enable as u8) << 3)
}
}

View File

@ -9,18 +9,18 @@
use esp32c3_hal::{
clock::ClockControl,
gpio::IO,
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
RtcCntl,
};
use esp_hal_common::ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
};
use esp_println;
use panic_halt as _;
use riscv_rt::entry;

View File

@ -13,10 +13,9 @@ use esp32c3_hal::{
interrupt,
pac::{self, Peripherals, TIMG0, TIMG1},
prelude::*,
timer::{Timer0, TimerGroup},
timer::{Timer, Timer0, TimerGroup},
RtcCntl,
};
use esp_hal_common::Timer;
use panic_halt as _;
use riscv_rt::entry;

View File

@ -52,11 +52,7 @@ fn main() -> ! {
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
pac::Interrupt::GPIO,
interrupt::Priority::Priority2,
)
.unwrap();
interrupt::enable(pac::Interrupt::GPIO, interrupt::Priority::Priority2).unwrap();
led.set_high().unwrap();

View File

@ -9,19 +9,19 @@
use esp32s2_hal::{
clock::ClockControl,
gpio::IO,
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
RtcCntl,
Serial,
};
use esp_hal_common::ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
};
use esp_println;
use panic_halt as _;
use xtensa_lx_rt::entry;

View File

@ -9,16 +9,16 @@ use core::cell::RefCell;
use esp32s2_hal::{
clock::ClockControl,
interrupt,
interrupt::Priority,
pac::{self, Peripherals},
prelude::*,
systimer::{Alarm, SystemTimer, Target},
timer::TimerGroup,
Delay,
interrupt::Priority,
RtcCntl,
};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, CriticalSectionMutex};
use xtensa_lx::mutex::{CriticalSectionMutex, Mutex};
use xtensa_lx_rt::entry;
static mut ALARM0: CriticalSectionMutex<RefCell<Option<Alarm<Target, 0>>>> =
@ -62,18 +62,9 @@ fn main() -> ! {
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
}
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET0,
Priority::Priority1,
).unwrap();
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET1,
Priority::Priority2,
).unwrap();
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET2,
Priority::Priority2,
).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET0, Priority::Priority1).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET1, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET2, Priority::Priority2).unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.

View File

@ -10,13 +10,13 @@ use core::{cell::RefCell, fmt::Write};
use esp32s2_hal::{
clock::ClockControl,
interrupt,
interrupt::Priority,
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
timer::{Timer, Timer0, Timer1, TimerGroup},
RtcCntl,
Serial,
};
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{CriticalSectionMutex, Mutex};
use xtensa_lx_rt::entry;

View File

@ -7,6 +7,7 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c::{self, I2C},
interrupt,
ledc,
macros,
pac,
prelude,

View File

@ -52,11 +52,7 @@ fn main() -> ! {
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
pac::Interrupt::GPIO,
interrupt::Priority::Priority2,
)
.unwrap();
interrupt::enable(pac::Interrupt::GPIO, interrupt::Priority::Priority2).unwrap();
led.set_high().unwrap();

View File

@ -9,19 +9,19 @@
use esp32s3_hal::{
clock::ClockControl,
gpio::IO,
ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
RtcCntl,
Serial,
};
use esp_hal_common::ledc::{
channel::{self, ChannelIFace},
timer::{self, TimerIFace},
LSGlobalClkSource,
LowSpeed,
LEDC,
};
use esp_println;
use panic_halt as _;
use xtensa_lx_rt::entry;
@ -51,15 +51,17 @@ fn main() -> ! {
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);
let mut lstimer0 = ledc.get_timer::<LowSpeed>(timer::Number::Timer2);
let mut lstimer0 = ledc.get_timer::<LowSpeed>(timer::Number::Timer0);
lstimer0
.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: 24u32.kHz(),
})
.unwrap();
let res = lstimer0.configure(timer::config::Config {
duty: timer::config::Duty::Duty5Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: 24u32.kHz(),
});
if res.is_err() {
esp_println::println!("oh no!");
}
let mut channel0 = ledc.get_channel(channel::Number::Channel0, led);
channel0

View File

@ -11,11 +11,10 @@ use esp32s3_hal::{
clock::ClockControl,
pac::{Peripherals, TIMG1},
prelude::*,
timer::{Timer0, TimerGroup},
timer::{Timer, Timer0, TimerGroup},
CpuControl,
RtcCntl,
};
use esp_hal_common::Timer;
use esp_println::println;
use nb::block;
use panic_halt as _;

View File

@ -9,12 +9,12 @@ use core::cell::RefCell;
use esp32s3_hal::{
clock::ClockControl,
interrupt,
interrupt::Priority,
pac::{self, Peripherals},
prelude::*,
systimer::{Alarm, SystemTimer, Target},
timer::TimerGroup,
Delay,
interrupt::Priority,
RtcCntl,
};
use panic_halt as _;
@ -62,18 +62,9 @@ fn main() -> ! {
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
}
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET0,
Priority::Priority1,
).unwrap();
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET1,
Priority::Priority2,
).unwrap();
interrupt::enable(
pac::Interrupt::SYSTIMER_TARGET2,
Priority::Priority2,
).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET0, Priority::Priority1).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET1, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::SYSTIMER_TARGET2, Priority::Priority2).unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.

View File

@ -10,13 +10,13 @@ use core::{cell::RefCell, fmt::Write};
use esp32s3_hal::{
clock::ClockControl,
interrupt,
interrupt::Priority,
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
timer::{Timer, Timer0, Timer1, TimerGroup},
RtcCntl,
Serial,
};
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;

View File

@ -10,6 +10,7 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c,
interrupt,
ledc,
macros,
pac,
prelude,