* Create the `esp32c6-hal` package * Teach `esp-hal-common` about the ESP32-C6 * Get a number of peripheral drivers building for the ESP32-C6 bckup initial clocks_ii * Create the `esp32c6-hal` package C6: update * Simplify and fix the linker script update * C6: add I2S * Create the `esp32c6-hal` package * Teach `esp-hal-common` about the ESP32-C6 * Get a number of peripheral drivers building for the ESP32-C6 bckup initial clocks_ii * Create the `esp32c6-hal` package * C6: update * Simplify and fix the linker script * update * C6: add I2S * update * C6 Interrupts * C6: Update build.rs, linker scripts and initial examples * C6: RMT * Fix interrupt handling * Fix `ClockControl::configure` * C6: revert to I2S0 instead of just I2S * C6: rebase and update * RTC not buildable * Implement RWDT and SWD disable * C6: working LEDC * C6: working RMT * C6: add aes * C6: add mcpwm * C6: add rtc_cntln - not finished * C6: update and formatting * C6: add pcnt * C6: add examples and format * Remove inline assembly, fix interrupts and linker scripts * Remove unused features, update cargo config for atomic emu, misc cleanup * Get ADC building and example "working" (as much as it ever does) * Remove a bunch of unused constants which were copied from ESP-IDF * The `mcpwm` example now works correctly * Get `TWAI` peripheral driver building for C6 * Clean up the `rtc_cntl` module and get all the other HALs building again * Add the C6 to our CI workflow * Fix various things that have been missed when rebasing Still missing a few examples (`clock_monitor`, `embassy_spi`, `ram`) * C6: Small updates in wdt (#1) * C6: Update WDT * C6: Update examples with WDT update * Update `esp-println` dependency to fix build errors * Fix formatting issues causing pre-commit hook to fail * Get some more examples working * Working `ram` example * Sync with changes in `main` after rebasing * Working `embassy_spi` example * Use a git dependency for the PAC until we publish a release * Fix I2S for ESP32-C6 * Fix esp32c6 direct boot (#4) * Add direct boot support for C6 * Fix direct boot for c6 - Actually copy into rtc ram - remove dummy section that is no longer needed (was just a waste of flash space) - Move RTC stuff before the no load sections * Update RWDT and refactor RTC (#3) * C6: Update RWDT and add example, refactor RTC and add not-really-good example * Update based on review comments, resolve bunch of warnings and run cargo fmt * Update C6 esp-pacs rev commit * Fix clocks_ll/esp32c6.rs * Fix riscv interrupts * Remove clock_monitor example for now * RAM example works in direct-boot mode * Add a TODO for &mut TIMG0 and cargo fmt * Fix linker script after a bad rebase * Update CI and Cargo.toml embassy required features * use riscv32imac-unknown-none-elf target for C6 in CI * change default target to riscv32imac-unknown-none-elf * add riscv32imac-unknown-none-elf target to MSRV job * another cleanup --------- Co-authored-by: bjoernQ <bjoern.quentin@mobile-j.de> Co-authored-by: Jesse Braham <jesse@beta7.io> * Make required changes to include new `RADIO` peripheral * Use published versions of PAC and `esp-println` * Use the correct target extensions (`imac`) * Fix the super watchdog timer, plus a few more examples * Fix UART clock configuration * Make sure to sync UART registers when configuring AT cmd detection * Disable APM in direct-boot mode * Address a number of review comments * Fix `SPI` clocks and `rtc_watchdog` example (#6) * fix SPI clocks * run cargo fmt * Add comment about used default clk src * Fix rtc_watchdog example in BL mode * run cargo fmt * Update rtc_watchdog example that it works in DB mode * README and example fixes/cleanup * Add I2C peripheral enable and reset * Fix `ApbSarAdc` configuration in `system.rs` --------- Co-authored-by: bjoernQ <bjoern.quentin@mobile-j.de> Co-authored-by: Juraj Sadel <juraj.sadel@espressif.com> Co-authored-by: Juraj Sadel <jurajsadel@gmail.com> Co-authored-by: Scott Mabin <scott@mabez.dev>
239 lines
7.2 KiB
Rust
239 lines
7.2 KiB
Rust
use core::{intrinsics::transmute, marker::PhantomData};
|
|
|
|
use fugit::MillisDurationU32;
|
|
|
|
use crate::{
|
|
peripheral::{Peripheral, PeripheralRef},
|
|
peripherals::{
|
|
generic::Reg,
|
|
systimer::{
|
|
target0_conf::TARGET0_CONF_SPEC,
|
|
target0_hi::TARGET0_HI_SPEC,
|
|
target0_lo::TARGET0_LO_SPEC,
|
|
},
|
|
SYSTIMER,
|
|
},
|
|
};
|
|
|
|
// TODO this only handles unit0 of the systimer
|
|
|
|
pub struct SystemTimer<'d> {
|
|
_inner: PeripheralRef<'d, SYSTIMER>,
|
|
pub alarm0: Alarm<Target, 0>,
|
|
pub alarm1: Alarm<Target, 1>,
|
|
pub alarm2: Alarm<Target, 2>,
|
|
}
|
|
|
|
impl<'d> SystemTimer<'d> {
|
|
#[cfg(esp32s2)]
|
|
pub const BIT_MASK: u64 = u64::MAX;
|
|
#[cfg(not(esp32s2))]
|
|
pub const BIT_MASK: u64 = 0xFFFFFFFFFFFFF;
|
|
|
|
#[cfg(esp32s2)]
|
|
pub const TICKS_PER_SECOND: u64 = 80_000_000; // TODO this can change when we have support for changing APB frequency
|
|
#[cfg(not(esp32s2))]
|
|
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
|
|
|
pub fn new(p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
|
crate::into_ref!(p);
|
|
Self {
|
|
_inner: p,
|
|
alarm0: Alarm::new(),
|
|
alarm1: Alarm::new(),
|
|
alarm2: Alarm::new(),
|
|
}
|
|
}
|
|
|
|
// TODO use fugit types
|
|
pub fn now() -> u64 {
|
|
// This should be safe to access from multiple contexts
|
|
// worst case scenario the second accesor ends up reading
|
|
// an older time stamp
|
|
let systimer = unsafe { &*SYSTIMER::ptr() };
|
|
systimer
|
|
.unit0_op
|
|
.modify(|_, w| w.timer_unit0_update().set_bit());
|
|
|
|
while !systimer
|
|
.unit0_op
|
|
.read()
|
|
.timer_unit0_value_valid()
|
|
.bit_is_set()
|
|
{}
|
|
|
|
let value_lo = systimer.unit0_value_lo.read().bits();
|
|
let value_hi = systimer.unit0_value_hi.read().bits();
|
|
|
|
((value_hi as u64) << 32) | value_lo as u64
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Target;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Periodic; // TODO, also impl e-h timer traits
|
|
|
|
#[derive(Debug)]
|
|
pub struct Alarm<MODE, const CHANNEL: u8> {
|
|
_pd: PhantomData<MODE>,
|
|
}
|
|
|
|
impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> {
|
|
// private constructor
|
|
fn new() -> Self {
|
|
Self { _pd: PhantomData }
|
|
}
|
|
|
|
pub fn interrupt_enable(&self, val: bool) {
|
|
let systimer = unsafe { &*SYSTIMER::ptr() };
|
|
match CHANNEL {
|
|
0 => systimer.int_ena.modify(|_, w| w.target0_int_ena().bit(val)),
|
|
1 => systimer.int_ena.modify(|_, w| w.target1_int_ena().bit(val)),
|
|
2 => systimer.int_ena.modify(|_, w| w.target2_int_ena().bit(val)),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
pub fn clear_interrupt(&self) {
|
|
let systimer = unsafe { &*SYSTIMER::ptr() };
|
|
match CHANNEL {
|
|
0 => systimer.int_clr.write(|w| w.target0_int_clr().set_bit()),
|
|
1 => systimer.int_clr.write(|w| w.target1_int_clr().set_bit()),
|
|
2 => systimer.int_clr.write(|w| w.target2_int_clr().set_bit()),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
fn configure(
|
|
&self,
|
|
conf: impl FnOnce(&Reg<TARGET0_CONF_SPEC>, &Reg<TARGET0_HI_SPEC>, &Reg<TARGET0_LO_SPEC>),
|
|
) {
|
|
unsafe {
|
|
let systimer = &*SYSTIMER::ptr();
|
|
let (tconf, hi, lo): (
|
|
&Reg<TARGET0_CONF_SPEC>,
|
|
&Reg<TARGET0_HI_SPEC>,
|
|
&Reg<TARGET0_LO_SPEC>,
|
|
) = match CHANNEL {
|
|
0 => (
|
|
&systimer.target0_conf,
|
|
&systimer.target0_hi,
|
|
&systimer.target0_lo,
|
|
),
|
|
1 => (
|
|
transmute(&systimer.target1_conf),
|
|
transmute(&systimer.target1_hi),
|
|
transmute(&systimer.target1_lo),
|
|
),
|
|
2 => (
|
|
transmute(&systimer.target2_conf),
|
|
transmute(&systimer.target2_hi),
|
|
transmute(&systimer.target2_lo),
|
|
),
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
#[cfg(esp32s2)]
|
|
systimer.step.write(|w| w.timer_xtal_step().bits(0x1)); // run at XTAL freq, not 80 * XTAL freq
|
|
|
|
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
|
{
|
|
tconf.write(|w| w.target0_timer_unit_sel().clear_bit()); // default, use unit 0
|
|
systimer
|
|
.conf
|
|
.modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit());
|
|
}
|
|
|
|
conf(tconf, hi, lo);
|
|
|
|
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
|
|
{
|
|
match CHANNEL {
|
|
0 => {
|
|
systimer
|
|
.comp0_load
|
|
.write(|w| w.timer_comp0_load().set_bit());
|
|
}
|
|
1 => systimer
|
|
.comp1_load
|
|
.write(|w| w.timer_comp1_load().set_bit()),
|
|
2 => systimer
|
|
.comp2_load
|
|
.write(|w| w.timer_comp2_load().set_bit()),
|
|
_ => unreachable!(),
|
|
}
|
|
|
|
systimer.conf.modify(|_r, w| match CHANNEL {
|
|
0 => w.target0_work_en().set_bit(),
|
|
1 => w.target1_work_en().set_bit(),
|
|
2 => w.target2_work_en().set_bit(),
|
|
_ => unreachable!(),
|
|
});
|
|
}
|
|
|
|
#[cfg(esp32s2)]
|
|
tconf.modify(|_r, w| match CHANNEL {
|
|
0 => w.target0_work_en().set_bit(),
|
|
1 => w.target0_work_en().set_bit(),
|
|
2 => w.target0_work_en().set_bit(),
|
|
_ => unreachable!(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<const CHANNEL: u8> Alarm<Target, CHANNEL> {
|
|
pub fn set_target(&self, timestamp: u64) {
|
|
self.configure(|tconf, hi, lo| unsafe {
|
|
tconf.write(|w| w.target0_period_mode().clear_bit()); // target mode
|
|
hi.write(|w| w.timer_target0_hi().bits((timestamp >> 32) as u32));
|
|
lo.write(|w| w.timer_target0_lo().bits((timestamp & 0xFFFF_FFFF) as u32));
|
|
})
|
|
}
|
|
|
|
pub fn into_periodic(self) -> Alarm<Periodic, CHANNEL> {
|
|
Alarm { _pd: PhantomData }
|
|
}
|
|
}
|
|
|
|
impl<const CHANNEL: u8> Alarm<Periodic, CHANNEL> {
|
|
pub fn set_period(&self, period: fugit::HertzU32) {
|
|
let time_period: MillisDurationU32 = period.into_duration();
|
|
let cycles = time_period.ticks();
|
|
self.configure(|tconf, hi, lo| unsafe {
|
|
tconf.write(|w| {
|
|
w.target0_period_mode()
|
|
.set_bit()
|
|
.target0_period()
|
|
.bits(cycles * (SystemTimer::TICKS_PER_SECOND as u32 / 1000))
|
|
});
|
|
hi.write(|w| w.timer_target0_hi().bits(0));
|
|
lo.write(|w| w.timer_target0_lo().bits(0));
|
|
})
|
|
}
|
|
|
|
pub fn into_target(self) -> Alarm<Target, CHANNEL> {
|
|
Alarm { _pd: PhantomData }
|
|
}
|
|
}
|
|
|
|
impl<T> Alarm<T, 0> {
|
|
pub const unsafe fn conjure() -> Self {
|
|
Self { _pd: PhantomData }
|
|
}
|
|
}
|
|
|
|
impl<T> Alarm<T, 1> {
|
|
pub const unsafe fn conjure() -> Self {
|
|
Self { _pd: PhantomData }
|
|
}
|
|
}
|
|
|
|
impl<T> Alarm<T, 2> {
|
|
pub const unsafe fn conjure() -> Self {
|
|
Self { _pd: PhantomData }
|
|
}
|
|
}
|