Skip to content

Commit

Permalink
Feature/time types (#64)
Browse files Browse the repository at this point in the history
* Use fugit time types for SPI peripheral, update examples

* initial WIP

* fix CI build errors

* Use extension trait in examples

Co-authored-by: Jesse Braham <[email protected]>
  • Loading branch information
JurajSadel and jessebraham authored May 31, 2022
1 parent 76a2067 commit b382a01
Show file tree
Hide file tree
Showing 19 changed files with 75 additions and 50 deletions.
1 change: 1 addition & 0 deletions esp-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
cfg-if = "1.0"
embedded-hal = { version = "0.2", features = ["unproven"] }
fugit = "0.3"
nb = "1.0"
paste = "1.0"
procmacros = { path = "../esp-hal-procmacros", package = "esp-hal-procmacros" }
Expand Down
14 changes: 9 additions & 5 deletions esp-hal-common/src/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ where

#[cfg(feature = "esp32c3")]
mod delay {
use fugit::HertzU64;

use crate::pac::SYSTIMER;

// The counters and comparators are driven using `XTAL_CLK`. The average clock
// frequency is fXTAL_CLK/2.5, which is 16 MHz. The timer counting is
// incremented by 1/16 μs on each `CNT_CLK` cycle.
const CLK_FREQ_HZ: u64 = 16_000_000;

const CLK_FREQ_HZ: HertzU64 = HertzU64::MHz(16);
/// Delay driver
///
/// Uses the `SYSTIMER` peripheral for counting clock cycles, as
Expand All @@ -60,7 +61,7 @@ mod delay {
/// Delay for the specified number of microseconds
pub fn delay(&self, us: u32) {
let t0 = self.unit0_value();
let clocks = (us as u64 * CLK_FREQ_HZ) / 1_000_000;
let clocks = (us as u64 * CLK_FREQ_HZ.raw()) / HertzU64::MHz(1).raw();

while self.unit0_value().wrapping_sub(t0) <= clocks {}
}
Expand Down Expand Up @@ -89,9 +90,12 @@ mod delay {

#[cfg(not(feature = "esp32c3"))]
mod delay {

use fugit::HertzU64;

// FIXME: The ESP32-S2 and ESP32-S3 have fixed crystal frequencies of 40MHz.
// This will not always be the case when using the ESP32.
const CLK_FREQ_HZ: u64 = 40_000_000;
const CLK_FREQ_HZ: HertzU64 = HertzU64::MHz(40);

/// Delay driver
///
Expand All @@ -107,7 +111,7 @@ mod delay {

/// Delay for the specified number of microseconds
pub fn delay(&self, us: u32) {
let clocks = (us as u64 * CLK_FREQ_HZ) / 1_000_000;
let clocks = (us as u64 * CLK_FREQ_HZ.raw()) / HertzU64::MHz(1).raw();
xtensa_lx::timer::delay(clocks as u32);
}
}
Expand Down
29 changes: 17 additions & 12 deletions esp-hal-common/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use core::convert::TryInto;

use embedded_hal::blocking::i2c::*;
use fugit::HertzU32;

use crate::{
gpio::{InputPin, OutputPin},
Expand All @@ -13,13 +14,13 @@ use crate::{

cfg_if::cfg_if! {
if #[cfg(feature = "esp32c3")] {
const SOURCE_CLK_FREQ: u32 = 40_000_000;
const SOURCE_CLK_FREQ: HertzU32 = HertzU32::MHz(40);
} else if #[cfg(feature = "esp32")] {
const SOURCE_CLK_FREQ: u32 = 80_000_000;
const SOURCE_CLK_FREQ: HertzU32 = HertzU32::MHz(80);
} else if #[cfg(feature = "esp32s2")] {
const SOURCE_CLK_FREQ: u32 = 80_000_000;
const SOURCE_CLK_FREQ: HertzU32 = HertzU32::MHz(80);
} else {
const SOURCE_CLK_FREQ: u32 = 40_000_000;
const SOURCE_CLK_FREQ: HertzU32 = HertzU32::MHz(40);
}
}

Expand Down Expand Up @@ -218,7 +219,7 @@ where
i2c: T,
mut sda: SDA,
mut scl: SCL,
frequency: u32,
frequency: HertzU32,
system: &mut System,
) -> Result<Self, SetupError> {
enable_peripheral(&i2c, system);
Expand Down Expand Up @@ -311,7 +312,7 @@ pub trait Instance {

fn i2c_number(&self) -> usize;

fn setup(&mut self, frequency: u32) -> Result<(), SetupError> {
fn setup(&mut self, frequency: HertzU32) -> Result<(), SetupError> {
// Reset entire peripheral (also resets fifo)
self.reset();

Expand Down Expand Up @@ -423,21 +424,25 @@ pub trait Instance {

/// Sets the frequency of the I2C interface by calculating and applying the
/// associated timings
fn set_frequency(&mut self, source_clk: u32, bus_freq: u32) -> Result<(), SetupError> {
fn set_frequency(
&mut self,
source_clk: HertzU32,
bus_freq: HertzU32,
) -> Result<(), SetupError> {
cfg_if::cfg_if! {
if #[cfg(any(feature = "esp32s3", feature = "esp32c3"))] {
// C3 and S3 have a clock devider mechanism, which we want to configure
// as high as possible.
let sclk_div: u8 = (source_clk / (bus_freq * 1024) + 1)
let sclk_div: u8 = (source_clk.raw() / (bus_freq.raw() * 1024) + 1)
.try_into()
.map_err(|_| SetupError::InvalidClkConfig)?;

let half_cycle: u16 = ((source_clk / sclk_div as u32 / bus_freq / 2) as u32)
let half_cycle: u16 = ((source_clk.raw() / sclk_div as u32 / bus_freq.raw() / 2) as u32)
.try_into()
.map_err(|_| SetupError::InvalidClkConfig)?;
} else {
// For EPS32 and the S2 variant no clock divider mechanism exists.
let half_cycle: u16 = (source_clk / (bus_freq * 2) as u32)
let half_cycle: u16 = (source_clk.raw() / (bus_freq.raw() * 2) as u32)
.try_into()
.map_err(|_| SetupError::InvalidClkConfig)?;
}
Expand All @@ -448,14 +453,14 @@ pub trait Instance {
// but improves readability)
cfg_if::cfg_if! {
if #[cfg(feature = "esp32c3")] {
let scl_wait_high: u8 = (if bus_freq <= 50000 { 0 } else { half_cycle / 8 })
let scl_wait_high: u8 = (if bus_freq.raw() <= 50000 { 0 } else { half_cycle / 8 })
.try_into()
.map_err(|_| SetupError::InvalidClkConfig)?;
let scl_high: u16 = half_cycle - scl_wait_high as u16;
let sda_hold = half_cycle / 4;
let sda_sample = scl_high / 2;
} else if #[cfg(feature = "esp32s3")] {
let scl_high = if bus_freq <= 50000 { half_cycle } else { half_cycle / 5 * 4 + 4 };
let scl_high = if bus_freq.raw() <= 50000 { half_cycle } else { half_cycle / 5 * 4 + 4 };
let scl_wait_high: u8 = (half_cycle - scl_high).try_into().map_err(|_| SetupError::InvalidClkConfig)?;
let sda_hold = half_cycle / 2;
let sda_sample = half_cycle / 2;
Expand Down
1 change: 1 addition & 0 deletions esp-hal-common/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ pub use embedded_hal::{
},
prelude::*,
};
pub use fugit::{ExtU32 as _, ExtU64 as _, RateExtU32 as _, RateExtU64 as _};
10 changes: 6 additions & 4 deletions esp-hal-common/src/pulse_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@

use core::slice::Iter;

use fugit::NanosDurationU32;

use crate::{
gpio::{types::OutputSignal, OutputPin},
pac::RMT,
Expand Down Expand Up @@ -169,11 +171,11 @@ pub struct PulseCode {
/// Logical output level in the first pulse code interval
pub level1: bool,
/// Length of the first pulse code interval (in clock cycles)
pub length1: u16,
pub length1: NanosDurationU32,
/// Logical output level in the second pulse code interval
pub level2: bool,
/// Length of the second pulse code interval (in clock cycles)
pub length2: u16,
pub length2: NanosDurationU32,
}

/// Convert a pulse code structure into a u32 value that can be written
Expand All @@ -185,7 +187,7 @@ impl From<PulseCode> for u32 {
// little-endian

// The length1 value resides in bits [14:0]
let mut entry: u32 = p.length1 as u32;
let mut entry: u32 = p.length1.ticks() as u32;

// If level1 is high, set bit 15, otherwise clear it
if p.level1 {
Expand All @@ -202,7 +204,7 @@ impl From<PulseCode> for u32 {
}

// The length2 value resides in bits [30:16]
entry |= (p.length2 as u32) << 16;
entry |= (p.length2.ticks() as u32) << 16;

entry
}
Expand Down
17 changes: 10 additions & 7 deletions esp-hal-common/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! mosi,
//! miso,
//! cs,
//! 100_000,
//! 100u32.kHz(),
//! embedded_hal::spi::MODE_0,
//! &mut peripherals.SYSTEM,
//! );
Expand All @@ -24,6 +24,7 @@
use core::convert::Infallible;

use embedded_hal::spi::{FullDuplex, Mode};
use fugit::{HertzU32, RateExtU32};

use crate::{
pac::spi2::RegisterBlock,
Expand Down Expand Up @@ -57,7 +58,7 @@ where
mut mosi: MOSI,
mut miso: MISO,
mut cs: CS,
frequency: u32,
frequency: HertzU32,
mode: Mode,
system: &mut System,
) -> Self {
Expand Down Expand Up @@ -184,15 +185,17 @@ pub trait Instance {
}

// taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496
fn setup(&mut self, frequency: u32) {
const APB_CLK_FREQ: u32 = 80_000_000; // TODO this might not be always true
fn setup(&mut self, frequency: HertzU32) {
// FIXME: this might not be always true
let apb_clk_freq: HertzU32 = 80u32.MHz();

let reg_val: u32;
let duty_cycle = 128;

// In HW, n, h and l fields range from 1 to 64, pre ranges from 1 to 8K.
// The value written to register is one lower than the used value.

if frequency > ((APB_CLK_FREQ / 4) * 3) {
if frequency > ((apb_clk_freq / 4) * 3) {
// Using APB frequency directly will give us the best result here.
reg_val = 1 << 31;
} else {
Expand All @@ -219,7 +222,7 @@ pub trait Instance {
* pre = round((APB_CLK_FREQ / n) / frequency)
*/

pre = ((APB_CLK_FREQ as i32/ n) + (frequency as i32 / 2)) / frequency as i32;
pre = ((apb_clk_freq.raw() as i32/ n) + (frequency.raw() as i32 / 2)) / frequency.raw() as i32;

if pre <= 0 {
pre = 1;
Expand All @@ -229,7 +232,7 @@ pub trait Instance {
pre = 16;
}

errval = (APB_CLK_FREQ as i32 / (pre as i32 * n as i32) - frequency as i32).abs();
errval = (apb_clk_freq.raw() as i32 / (pre as i32 * n as i32) - frequency.raw() as i32).abs();
if bestn == -1 || errval <= besterr {
besterr = errval;
bestn = n as i32;
Expand Down
13 changes: 9 additions & 4 deletions esp-hal-common/src/utils/smart_leds_adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use core::{marker::PhantomData, slice::IterMut};

use fugit::NanosDuration;
use smart_leds_trait::{SmartLedsWrite, RGB8};

#[cfg(any(feature = "esp32", feature = "esp32s2"))]
Expand Down Expand Up @@ -42,10 +43,14 @@ const SK68XX_T0L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T0H_NS;
const SK68XX_T1H_NS: u32 = 640;
const SK68XX_T1L_NS: u32 = SK68XX_CODE_PERIOD - SK68XX_T1H_NS;

const SK68XX_T0H_CYCLES: u16 = ((SK68XX_T0H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T0L_CYCLES: u16 = ((SK68XX_T0L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T1H_CYCLES: u16 = ((SK68XX_T1H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T1L_CYCLES: u16 = ((SK68XX_T1L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500) as u16;
const SK68XX_T0H_CYCLES: NanosDuration<u32> =
NanosDuration::<u32>::from_ticks((SK68XX_T0H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500);
const SK68XX_T0L_CYCLES: NanosDuration<u32> =
NanosDuration::<u32>::from_ticks((SK68XX_T0L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500);
const SK68XX_T1H_CYCLES: NanosDuration<u32> =
NanosDuration::<u32>::from_ticks((SK68XX_T1H_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500);
const SK68XX_T1L_CYCLES: NanosDuration<u32> =
NanosDuration::<u32>::from_ticks((SK68XX_T1L_NS * (SOURCE_CLK_FREQ / 1_000_000)) / 500);

/// All types of errors that can happen during the conversion and transmission
/// of LED commands
Expand Down
1 change: 1 addition & 0 deletions esp32-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ categories = [
[dependencies]
bare-metal = "1.0"
embedded-hal = { version = "0.2", features = ["unproven"] }
fugit = "0.3"
nb = "1.0"
void = { version = "1.0", default-features = false }
xtensa-lx = { version = "0.7", features = ["esp32"] }
Expand Down
2 changes: 1 addition & 1 deletion esp32-hal/examples/i2c_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn main() -> ! {
peripherals.I2C0,
io.pins.gpio32,
io.pins.gpio33,
100_000,
100u32.kHz(),
&mut peripherals.DPORT,
)
.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions esp32-hal/examples/spi_loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@ fn main() -> ! {
mosi,
miso,
cs,
100_000,
100u32.kHz(),
embedded_hal::spi::MODE_0,
&mut peripherals.DPORT,
);

let delay = Delay::new();
let mut delay = Delay::new();

loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();

delay.delay(250_000);
delay.delay_ms(250u32);
}
}
5 changes: 3 additions & 2 deletions esp32c3-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ categories = [
[dependencies]
bare-metal = "1.0"
embedded-hal = { version = "0.2", features = ["unproven"] }
fugit = "0.3"
nb = "1.0"
r0 = "1.0.0"
riscv = "0.8.0"
r0 = "1.0"
riscv = "0.8"
riscv-rt = { version = "0.8", optional = true }
void = { version = "1.0", default-features = false }

Expand Down
2 changes: 1 addition & 1 deletion esp32c3-hal/examples/i2c_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn main() -> ! {
peripherals.I2C0,
io.pins.gpio1,
io.pins.gpio2,
100_000,
100u32.kHz(),
&mut peripherals.SYSTEM,
)
.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions esp32c3-hal/examples/spi_loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,18 @@ fn main() -> ! {
mosi,
miso,
cs,
100_000,
100u32.kHz(),
embedded_hal::spi::MODE_0,
&mut peripherals.SYSTEM,
);

let delay = Delay::new(peripherals.SYSTIMER);
let mut delay = Delay::new(peripherals.SYSTIMER);

loop {
let mut data = [0xde, 0xca, 0xfb, 0xad];
spi.transfer(&mut data).unwrap();
writeln!(serial0, "{:x?}", data).ok();

delay.delay(250_000);
delay.delay_ms(250u32);
}
}
1 change: 1 addition & 0 deletions esp32s2-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ categories = [
[dependencies]
bare-metal = "1.0"
embedded-hal = { version = "0.2", features = ["unproven"] }
fugit = "0.3"
nb = "1.0"
void = { version = "1.0", default-features = false }
xtensa-lx = { version = "0.7", features = ["esp32s2"] }
Expand Down
2 changes: 1 addition & 1 deletion esp32s2-hal/examples/i2c_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn main() -> ! {
peripherals.I2C0,
io.pins.gpio35,
io.pins.gpio36,
100_000,
100u32.kHz(),
&mut peripherals.SYSTEM,
)
.unwrap();
Expand Down
Loading

0 comments on commit b382a01

Please sign in to comment.