Interrupt flags

This commit is contained in:
ivmarkov 2023-05-13 10:07:38 +00:00
parent 01d35f3973
commit ba9cc4246a
11 changed files with 306 additions and 50 deletions

View File

@ -29,7 +29,7 @@ fn main() -> Result<()> {
// 3 seconds white at 10% brightness // 3 seconds white at 10% brightness
neopixel( neopixel(
RGB { Rgb {
r: 25, r: 25,
g: 25, g: 25,
b: 25, b: 25,
@ -51,7 +51,7 @@ fn main() -> Result<()> {
} }
} }
struct RGB { struct Rgb {
r: u8, r: u8,
g: u8, g: u8,
b: u8, b: u8,
@ -61,7 +61,7 @@ fn ns(nanos: u64) -> Duration {
Duration::from_nanos(nanos) Duration::from_nanos(nanos)
} }
fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> Result<()> { fn neopixel(rgb: Rgb, tx: &mut TxRmtDriver) -> Result<()> {
// e.g. rgb: (1,2,4) // e.g. rgb: (1,2,4)
// G R B // G R B
// 7 0 7 0 7 0 // 7 0 7 0 7 0
@ -85,7 +85,7 @@ fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> Result<()> {
} }
/// Converts hue, saturation, value to RGB /// Converts hue, saturation, value to RGB
fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<RGB> { fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<Rgb> {
if h > 360 || s > 100 || v > 100 { if h > 360 || s > 100 || v > 100 {
bail!("The given HSV values are not in valid range"); bail!("The given HSV values are not in valid range");
} }
@ -99,19 +99,19 @@ fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<RGB> {
r = c; r = c;
g = x; g = x;
b = 0.0; b = 0.0;
} else if h >= 60 && h < 120 { } else if (60..120).contains(&h) {
r = x; r = x;
g = c; g = c;
b = 0.0; b = 0.0;
} else if h >= 120 && h < 180 { } else if (120..180).contains(&h) {
r = 0.0; r = 0.0;
g = c; g = c;
b = x; b = x;
} else if h >= 180 && h < 240 { } else if (180..240).contains(&h) {
r = 0.0; r = 0.0;
g = x; g = x;
b = c; b = c;
} else if h >= 240 && h < 300 { } else if (240..300).contains(&h) {
r = x; r = x;
g = 0.0; g = 0.0;
b = c; b = c;
@ -121,7 +121,7 @@ fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<RGB> {
b = x; b = x;
} }
Ok(RGB { Ok(Rgb {
r: ((r + m) * 255.0) as u8, r: ((r + m) * 255.0) as u8,
g: ((g + m) * 255.0) as u8, g: ((g + m) * 255.0) as u8,
b: ((b + m) * 255.0) as u8, b: ((b + m) * 255.0) as u8,

View File

@ -32,7 +32,13 @@ fn main() -> anyhow::Result<()> {
println!("Starting SPI loopback test"); println!("Starting SPI loopback test");
let driver = SpiDriver::new::<SPI2>(spi, sclk, serial_out, Some(serial_in), Dma::Disabled)?; let driver = SpiDriver::new::<SPI2>(
spi,
sclk,
serial_out,
Some(serial_in),
&SpiDriverConfig::new(),
)?;
let config_1 = config::Config::new().baudrate(26.MHz().into()); let config_1 = config::Config::new().baudrate(26.MHz().into());
let mut device_1 = SpiDeviceDriver::new(&driver, Some(cs_1), &config_1)?; let mut device_1 = SpiDeviceDriver::new(&driver, Some(cs_1), &config_1)?;

View File

@ -52,8 +52,15 @@ fn main() -> anyhow::Result<()> {
.baudrate(26.MHz().into()) .baudrate(26.MHz().into())
.data_mode(MODE_3); .data_mode(MODE_3);
let device = let device = SpiDeviceDriver::new_single(
SpiDeviceDriver::new_single(spi, sclk, sda, Some(sdi), Dma::Disabled, Some(cs), &config)?; spi,
sclk,
sda,
Some(sdi),
Some(cs),
&SpiDriverConfig::new(),
&config,
)?;
// display interface abstraction from SPI and DC // display interface abstraction from SPI and DC
let di = SPIInterfaceNoCS::new(device, dc); let di = SPIInterfaceNoCS::new(device, dc);

View File

@ -36,6 +36,7 @@ use esp_idf_sys::*;
use crate::delay::{BLOCK, NON_BLOCK}; use crate::delay::{BLOCK, NON_BLOCK};
use crate::gpio::*; use crate::gpio::*;
use crate::interrupt::IntrFlags;
use crate::peripheral::{Peripheral, PeripheralRef}; use crate::peripheral::{Peripheral, PeripheralRef};
crate::embedded_hal_error!(CanError, embedded_can::Error, embedded_can::ErrorKind); crate::embedded_hal_error!(CanError, embedded_can::Error, embedded_can::ErrorKind);
@ -49,8 +50,11 @@ crate::embedded_hal_error!(
pub type CanConfig = config::Config; pub type CanConfig = config::Config;
pub mod config { pub mod config {
use enumset::EnumSet;
use esp_idf_sys::*; use esp_idf_sys::*;
use crate::interrupt::IntrFlags;
/// CAN timing /// CAN timing
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Timing { pub enum Timing {
@ -433,7 +437,7 @@ pub mod config {
} }
} }
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub timing: Timing, pub timing: Timing,
pub filter: Filter, pub filter: Filter,
@ -441,14 +445,19 @@ pub mod config {
pub rx_queue_len: u32, pub rx_queue_len: u32,
pub mode: Mode, pub mode: Mode,
pub alerts: Alerts, pub alerts: Alerts,
pub intr_flags: EnumSet<IntrFlags>,
} }
impl Config { impl Config {
pub fn new() -> Self { pub fn new() -> Self {
Config { Self {
timing: Default::default(),
filter: Default::default(),
tx_queue_len: 5, tx_queue_len: 5,
rx_queue_len: 5, rx_queue_len: 5,
..Default::default() mode: Default::default(),
alerts: Default::default(),
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
@ -464,25 +473,41 @@ pub mod config {
self self
} }
#[must_use]
pub fn tx_queue_len(mut self, tx_queue_len: u32) -> Self { pub fn tx_queue_len(mut self, tx_queue_len: u32) -> Self {
self.tx_queue_len = tx_queue_len; self.tx_queue_len = tx_queue_len;
self self
} }
#[must_use]
pub fn rx_queue_len(mut self, rx_queue_len: u32) -> Self { pub fn rx_queue_len(mut self, rx_queue_len: u32) -> Self {
self.rx_queue_len = rx_queue_len; self.rx_queue_len = rx_queue_len;
self self
} }
#[must_use]
pub fn mode(mut self, mode: Mode) -> Self { pub fn mode(mut self, mode: Mode) -> Self {
self.mode = mode; self.mode = mode;
self self
} }
#[must_use]
pub fn alerts(mut self, alerts: Alerts) -> Self { pub fn alerts(mut self, alerts: Alerts) -> Self {
self.alerts = alerts; self.alerts = alerts;
self self
} }
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = flags;
self
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
} }
} }
@ -510,7 +535,7 @@ impl<'d> CanDriver<'d> {
rx_queue_len: config.rx_queue_len, rx_queue_len: config.rx_queue_len,
alerts_enabled: config.alerts.into(), alerts_enabled: config.alerts.into(),
clkout_divider: 0, clkout_divider: 0,
intr_flags: ESP_INTR_FLAG_LEVEL1 as i32, intr_flags: IntrFlags::to_native(config.intr_flags) as _,
}; };
let timing_config = config.timing.into(); let timing_config = config.timing.into();

View File

@ -1319,22 +1319,33 @@ impl UnsafeCallback {
} }
} }
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))] #[cfg(not(feature = "riscv-ulp-hal"))]
static ISR_ALLOC_FLAGS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
#[cfg(not(feature = "riscv-ulp-hal"))]
static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool = static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool =
core::sync::atomic::AtomicBool::new(false); core::sync::atomic::AtomicBool::new(false);
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))] #[cfg(not(feature = "riscv-ulp-hal"))]
static ISR_SERVICE_ENABLED_CS: crate::task::CriticalSection = crate::task::CriticalSection::new(); static ISR_SERVICE_ENABLED_CS: crate::task::CriticalSection = crate::task::CriticalSection::new();
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))] #[cfg(not(feature = "riscv-ulp-hal"))]
fn enable_isr_service() -> Result<(), EspError> { pub fn init_isr_alloc_flags(flags: enumset::EnumSet<crate::interrupt::IntrFlags>) {
ISR_ALLOC_FLAGS.store(
crate::interrupt::IntrFlags::to_native(flags),
core::sync::atomic::Ordering::SeqCst,
);
}
#[cfg(not(feature = "riscv-ulp-hal"))]
pub fn enable_isr_service() -> Result<(), EspError> {
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) { if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) {
let _guard = ISR_SERVICE_ENABLED_CS.enter(); let _guard = ISR_SERVICE_ENABLED_CS.enter();
if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) { if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) {
esp!(unsafe { gpio_install_isr_service(0) })?; esp!(unsafe { gpio_install_isr_service(ISR_ALLOC_FLAGS.load(Ordering::SeqCst) as _) })?;
ISR_SERVICE_ENABLED.store(true, Ordering::SeqCst); ISR_SERVICE_ENABLED.store(true, Ordering::SeqCst);
} }

View File

@ -7,6 +7,7 @@ use esp_idf_sys::*;
use crate::delay::*; use crate::delay::*;
use crate::gpio::*; use crate::gpio::*;
use crate::interrupt::IntrFlags;
use crate::peripheral::Peripheral; use crate::peripheral::Peripheral;
use crate::units::*; use crate::units::*;
@ -36,16 +37,19 @@ pub type I2cSlaveConfig = config::SlaveConfig;
/// I2C configuration /// I2C configuration
pub mod config { pub mod config {
use enumset::EnumSet;
use super::APBTickType; use super::APBTickType;
use crate::units::*; use crate::{interrupt::IntrFlags, units::*};
/// I2C Master configuration /// I2C Master configuration
#[derive(Copy, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub baudrate: Hertz, pub baudrate: Hertz,
pub sda_pullup_enabled: bool, pub sda_pullup_enabled: bool,
pub scl_pullup_enabled: bool, pub scl_pullup_enabled: bool,
pub timeout: Option<APBTickType>, pub timeout: Option<APBTickType>,
pub intr_flags: EnumSet<IntrFlags>,
} }
impl Config { impl Config {
@ -76,6 +80,12 @@ pub mod config {
self.timeout = Some(timeout); self.timeout = Some(timeout);
self self
} }
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = flags;
self
}
} }
impl Default for Config { impl Default for Config {
@ -85,18 +95,20 @@ pub mod config {
sda_pullup_enabled: true, sda_pullup_enabled: true,
scl_pullup_enabled: true, scl_pullup_enabled: true,
timeout: None, timeout: None,
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
} }
/// I2C Slave configuration /// I2C Slave configuration
#[cfg(not(esp32c2))] #[cfg(not(esp32c2))]
#[derive(Copy, Clone)] #[derive(Debug, Clone)]
pub struct SlaveConfig { pub struct SlaveConfig {
pub sda_pullup_enabled: bool, pub sda_pullup_enabled: bool,
pub scl_pullup_enabled: bool, pub scl_pullup_enabled: bool,
pub rx_buf_len: usize, pub rx_buf_len: usize,
pub tx_buf_len: usize, pub tx_buf_len: usize,
pub intr_flags: EnumSet<IntrFlags>,
} }
#[cfg(not(esp32c2))] #[cfg(not(esp32c2))]
@ -128,6 +140,12 @@ pub mod config {
self.tx_buf_len = len; self.tx_buf_len = len;
self self
} }
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = flags;
self
}
} }
#[cfg(not(esp32c2))] #[cfg(not(esp32c2))]
@ -138,6 +156,7 @@ pub mod config {
scl_pullup_enabled: true, scl_pullup_enabled: true,
rx_buf_len: 0, rx_buf_len: 0,
tx_buf_len: 0, tx_buf_len: 0,
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
} }
@ -188,8 +207,8 @@ impl<'d> I2cDriver<'d> {
i2c_mode_t_I2C_MODE_MASTER, i2c_mode_t_I2C_MODE_MASTER,
0, // Not used in master mode 0, // Not used in master mode
0, // Not used in master mode 0, // Not used in master mode
0, IntrFlags::to_native(config.intr_flags) as _,
) // TODO: set flags )
})?; })?;
if let Some(timeout) = config.timeout { if let Some(timeout) = config.timeout {
@ -460,7 +479,7 @@ impl<'d> I2cSlaveDriver<'d> {
i2c_mode_t_I2C_MODE_SLAVE, i2c_mode_t_I2C_MODE_SLAVE,
config.rx_buf_len, config.rx_buf_len,
config.tx_buf_len, config.tx_buf_len,
0, // TODO: set flags IntrFlags::to_native(config.intr_flags) as _,
) )
})?; })?;

View File

@ -1,7 +1,82 @@
use core::sync::atomic::{AtomicU64, Ordering}; use core::sync::atomic::{AtomicU64, Ordering};
use enumset::{EnumSet, EnumSetType};
use esp_idf_sys::*; use esp_idf_sys::*;
/// Interrupt allocation flags.
/// These flags can be used to specify which interrupt qualities the code calling esp_intr_alloc* needs.
#[derive(Debug, EnumSetType)]
pub enum IntrFlags {
// Accept a Level 1 interrupt vector (lowest priority)
Level1,
// Accept a Level 2 interrupt vector.
Level2,
// Accept a Level 3 interrupt vector.
Level3,
// Accept a Level 4 interrupt vector.
Level4,
// Accept a Level 5 interrupt vector.
Level5,
// Accept a Level 6 interrupt vector.
Level6,
// Accept a Level 7 interrupt vector (highest priority)
Nmi,
// Interrupt can be shared between ISRs.
Shared,
// Edge-triggered interrupt.
Edge,
// ISR can be called if cache is disabled.
// Must be used with a proper option *_ISR_IN_IRAM in SDKCONFIG
Iram,
// Return with this interrupt disabled.
IntrDisabled,
// Low and medium prio interrupts. These can be handled in C.
LowMed,
// High level interrupts. Need to be handled in assembly.
High,
}
impl IntrFlags {
pub fn levels(&self) -> EnumSet<Self> {
Self::Level1
| Self::Level2
| Self::Level3
| Self::Level4
| Self::Level5
| Self::Level6
| Self::Nmi
}
pub(crate) fn to_native(flags: EnumSet<Self>) -> u32 {
let mut uflags: u32 = 0;
for flag in flags {
uflags |= u32::from(flag);
}
uflags
}
}
impl From<IntrFlags> for u32 {
fn from(flag: IntrFlags) -> Self {
match flag {
IntrFlags::Level1 => esp_idf_sys::ESP_INTR_FLAG_LEVEL1,
IntrFlags::Level2 => esp_idf_sys::ESP_INTR_FLAG_LEVEL2,
IntrFlags::Level3 => esp_idf_sys::ESP_INTR_FLAG_LEVEL3,
IntrFlags::Level4 => esp_idf_sys::ESP_INTR_FLAG_LEVEL4,
IntrFlags::Level5 => esp_idf_sys::ESP_INTR_FLAG_LEVEL5,
IntrFlags::Level6 => esp_idf_sys::ESP_INTR_FLAG_LEVEL6,
IntrFlags::Nmi => esp_idf_sys::ESP_INTR_FLAG_NMI,
IntrFlags::Shared => esp_idf_sys::ESP_INTR_FLAG_SHARED,
IntrFlags::Edge => esp_idf_sys::ESP_INTR_FLAG_EDGE,
IntrFlags::Iram => esp_idf_sys::ESP_INTR_FLAG_IRAM,
IntrFlags::IntrDisabled => esp_idf_sys::ESP_INTR_FLAG_INTRDISABLED,
IntrFlags::LowMed => esp_idf_sys::ESP_INTR_FLAG_LOWMED,
IntrFlags::High => esp_idf_sys::ESP_INTR_FLAG_HIGH,
}
}
}
pub(crate) static CS: IsrCriticalSection = IsrCriticalSection::new(); pub(crate) static CS: IsrCriticalSection = IsrCriticalSection::new();
/// Returns true if the currently active core is executing an ISR request /// Returns true if the currently active core is executing an ISR request

View File

@ -515,6 +515,8 @@ impl Drop for PcntDriver<'_> {
} }
} }
static ISR_ALLOC_FLAGS: core::sync::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool = static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool =
core::sync::atomic::AtomicBool::new(false); core::sync::atomic::AtomicBool::new(false);
@ -522,6 +524,13 @@ static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool =
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
static PCNT_CS: crate::task::CriticalSection = crate::task::CriticalSection::new(); static PCNT_CS: crate::task::CriticalSection = crate::task::CriticalSection::new();
pub fn init_isr_alloc_flags(flags: enumset::EnumSet<crate::interrupt::IntrFlags>) {
ISR_ALLOC_FLAGS.store(
crate::interrupt::IntrFlags::to_native(flags),
core::sync::atomic::Ordering::SeqCst,
);
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn enable_isr_service() -> Result<(), EspError> { fn enable_isr_service() -> Result<(), EspError> {
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
@ -530,7 +539,7 @@ fn enable_isr_service() -> Result<(), EspError> {
let _cs = PCNT_CS.enter(); let _cs = PCNT_CS.enter();
if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) { if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) {
esp!(unsafe { pcnt_isr_service_install(0) })?; esp!(unsafe { pcnt_isr_service_install(ISR_ALLOC_FLAGS.load(Ordering::SeqCst) as _) })?;
ISR_SERVICE_ENABLED.store(true, Ordering::SeqCst); ISR_SERVICE_ENABLED.store(true, Ordering::SeqCst);
} }

View File

@ -64,6 +64,7 @@ use esp_idf_sys::*;
use crate::gpio::InputPin; use crate::gpio::InputPin;
use crate::gpio::OutputPin; use crate::gpio::OutputPin;
use crate::interrupt::IntrFlags;
use crate::peripheral::Peripheral; use crate::peripheral::Peripheral;
use crate::units::Hertz; use crate::units::Hertz;
@ -250,10 +251,14 @@ pub type RxRmtConfig = config::ReceiveConfig;
/// ///
/// ``` /// ```
pub mod config { pub mod config {
use enumset::EnumSet;
use esp_idf_sys::{EspError, ESP_ERR_INVALID_ARG}; use esp_idf_sys::{EspError, ESP_ERR_INVALID_ARG};
use super::PinState; use super::PinState;
use crate::units::{FromValueType, Hertz}; use crate::{
interrupt::IntrFlags,
units::{FromValueType, Hertz},
};
/// A percentage from 0 to 100%, used to specify the duty percentage in [`CarrierConfig`]. /// A percentage from 0 to 100%, used to specify the duty percentage in [`CarrierConfig`].
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
@ -292,16 +297,19 @@ pub mod config {
} }
} }
#[must_use]
pub fn frequency(mut self, hz: Hertz) -> Self { pub fn frequency(mut self, hz: Hertz) -> Self {
self.frequency = hz; self.frequency = hz;
self self
} }
#[must_use]
pub fn carrier_level(mut self, state: PinState) -> Self { pub fn carrier_level(mut self, state: PinState) -> Self {
self.carrier_level = state; self.carrier_level = state;
self self
} }
#[must_use]
pub fn duty_percent(mut self, duty: DutyPercent) -> Self { pub fn duty_percent(mut self, duty: DutyPercent) -> Self {
self.duty_percent = duty; self.duty_percent = duty;
self self
@ -329,6 +337,7 @@ pub mod config {
} }
/// Used when creating a [`Transmit`][crate::rmt::Transmit] instance. /// Used when creating a [`Transmit`][crate::rmt::Transmit] instance.
#[derive(Debug, Clone)]
pub struct TransmitConfig { pub struct TransmitConfig {
pub clock_divider: u8, pub clock_divider: u8,
pub mem_block_num: u8, pub mem_block_num: u8,
@ -344,6 +353,8 @@ pub mod config {
/// When set, RMT channel will take REF_TICK or XTAL as source clock. The benefit is, RMT /// When set, RMT channel will take REF_TICK or XTAL as source clock. The benefit is, RMT
/// channel can continue work even when APB clock is changing. /// channel can continue work even when APB clock is changing.
pub aware_dfs: bool, pub aware_dfs: bool,
pub intr_flags: EnumSet<IntrFlags>,
} }
impl TransmitConfig { impl TransmitConfig {
@ -355,38 +366,51 @@ pub mod config {
looping: Loop::None, looping: Loop::None,
carrier: None, carrier: None,
idle: Some(PinState::Low), idle: Some(PinState::Low),
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
#[must_use]
pub fn aware_dfs(mut self, enable: bool) -> Self { pub fn aware_dfs(mut self, enable: bool) -> Self {
self.aware_dfs = enable; self.aware_dfs = enable;
self self
} }
#[must_use]
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self { pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
self.mem_block_num = mem_block_num; self.mem_block_num = mem_block_num;
self self
} }
#[must_use]
pub fn clock_divider(mut self, divider: u8) -> Self { pub fn clock_divider(mut self, divider: u8) -> Self {
self.clock_divider = divider; self.clock_divider = divider;
self self
} }
#[must_use]
pub fn looping(mut self, looping: Loop) -> Self { pub fn looping(mut self, looping: Loop) -> Self {
self.looping = looping; self.looping = looping;
self self
} }
#[must_use]
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self { pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
self.carrier = carrier; self.carrier = carrier;
self self
} }
#[must_use]
pub fn idle(mut self, idle: Option<PinState>) -> Self { pub fn idle(mut self, idle: Option<PinState>) -> Self {
self.idle = idle; self.idle = idle;
self self
} }
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = flags;
self
}
} }
impl Default for TransmitConfig { impl Default for TransmitConfig {
@ -397,6 +421,7 @@ pub mod config {
} }
/// Used when creating a [`Receive`][crate::rmt::Receive] instance. /// Used when creating a [`Receive`][crate::rmt::Receive] instance.
#[derive(Debug, Clone)]
pub struct ReceiveConfig { pub struct ReceiveConfig {
pub clock_divider: u8, pub clock_divider: u8,
pub mem_block_num: u8, pub mem_block_num: u8,
@ -404,6 +429,7 @@ pub mod config {
pub filter_ticks_thresh: u8, pub filter_ticks_thresh: u8,
pub filter_en: bool, pub filter_en: bool,
pub carrier: Option<CarrierConfig>, pub carrier: Option<CarrierConfig>,
pub intr_flags: EnumSet<IntrFlags>,
} }
impl ReceiveConfig { impl ReceiveConfig {
@ -411,35 +437,47 @@ pub mod config {
Self::default() Self::default()
} }
#[must_use]
pub fn clock_divider(mut self, divider: u8) -> Self { pub fn clock_divider(mut self, divider: u8) -> Self {
self.clock_divider = divider; self.clock_divider = divider;
self self
} }
#[must_use]
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self { pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
self.mem_block_num = mem_block_num; self.mem_block_num = mem_block_num;
self self
} }
#[must_use]
pub fn idle_threshold(mut self, threshold: u16) -> Self { pub fn idle_threshold(mut self, threshold: u16) -> Self {
self.idle_threshold = threshold; self.idle_threshold = threshold;
self self
} }
#[must_use]
pub fn filter_ticks_thresh(mut self, threshold: u8) -> Self { pub fn filter_ticks_thresh(mut self, threshold: u8) -> Self {
self.filter_ticks_thresh = threshold; self.filter_ticks_thresh = threshold;
self self
} }
#[must_use]
pub fn filter_en(mut self, enable: bool) -> Self { pub fn filter_en(mut self, enable: bool) -> Self {
self.filter_en = enable; self.filter_en = enable;
self self
} }
#[must_use]
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self { pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
self.carrier = carrier; self.carrier = carrier;
self self
} }
#[must_use]
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = flags;
self
}
} }
impl Default for ReceiveConfig { impl Default for ReceiveConfig {
@ -452,6 +490,7 @@ pub mod config {
filter_ticks_thresh: 100, // 100 microseconds, pulses less than this will be ignored filter_ticks_thresh: 100, // 100 microseconds, pulses less than this will be ignored
filter_en: true, filter_en: true,
carrier: None, carrier: None,
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
} }
@ -520,7 +559,11 @@ impl<'d> TxRmtDriver<'d> {
unsafe { unsafe {
esp!(rmt_config(&sys_config))?; esp!(rmt_config(&sys_config))?;
esp!(rmt_driver_install(C::channel(), 0, 0))?; esp!(rmt_driver_install(
C::channel(),
0,
IntrFlags::to_native(config.intr_flags) as _
))?;
} }
Ok(Self { Ok(Self {
@ -943,7 +986,7 @@ impl<'d> RxRmtDriver<'d> {
#[cfg(not(any(esp32, esp32c2)))] #[cfg(not(any(esp32, esp32c2)))]
let carrier = config.carrier.unwrap_or_default(); let carrier = config.carrier.unwrap_or_default();
let config = rmt_config_t { let sys_config = rmt_config_t {
rmt_mode: rmt_mode_t_RMT_MODE_RX, rmt_mode: rmt_mode_t_RMT_MODE_RX,
channel: C::channel(), channel: C::channel(),
gpio_num: pin.pin(), gpio_num: pin.pin(),
@ -968,8 +1011,12 @@ impl<'d> RxRmtDriver<'d> {
}; };
unsafe { unsafe {
esp!(rmt_config(&config))?; esp!(rmt_config(&sys_config))?;
esp!(rmt_driver_install(C::channel(), ring_buf_size * 4, 0))?; esp!(rmt_driver_install(
C::channel(),
ring_buf_size * 4,
IntrFlags::to_native(config.intr_flags) as _
))?;
} }
Ok(Self { Ok(Self {

View File

@ -45,6 +45,7 @@ use esp_idf_sys::*;
use crate::delay::{Ets, BLOCK}; use crate::delay::{Ets, BLOCK};
use crate::gpio::{AnyOutputPin, InputPin, Level, Output, OutputPin, PinDriver}; use crate::gpio::{AnyOutputPin, InputPin, Level, Output, OutputPin, PinDriver};
use crate::interrupt::IntrFlags;
use crate::peripheral::Peripheral; use crate::peripheral::Peripheral;
use crate::task::CriticalSection; use crate::task::CriticalSection;
@ -96,13 +97,17 @@ impl Dma {
} }
} }
pub type SpiDriverConfig = config::DriverConfig;
pub type SpiConfig = config::Config; pub type SpiConfig = config::Config;
/// SPI configuration /// SPI configuration
pub mod config { pub mod config {
use crate::units::*; use crate::{interrupt::IntrFlags, units::*};
use enumset::EnumSet;
use esp_idf_sys::*; use esp_idf_sys::*;
use super::Dma;
pub struct V02Type<T>(pub T); pub struct V02Type<T>(pub T);
impl From<V02Type<embedded_hal_0_2::spi::Polarity>> for embedded_hal::spi::Polarity { impl From<V02Type<embedded_hal_0_2::spi::Polarity>> for embedded_hal::spi::Polarity {
@ -137,7 +142,7 @@ pub mod config {
} }
/// Specify the communication mode with the device /// Specify the communication mode with the device
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Duplex { pub enum Duplex {
/// Full duplex is the default /// Full duplex is the default
Full, Full,
@ -158,7 +163,7 @@ pub mod config {
} }
/// Specifies the order in which the bits of data should be transfered/received /// Specifies the order in which the bits of data should be transfered/received
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BitOrder { pub enum BitOrder {
/// Most significant bit first (default) /// Most significant bit first (default)
MsbFirst, MsbFirst,
@ -181,8 +186,42 @@ pub mod config {
} }
} }
/// SPI Driver configuration
#[derive(Debug, Clone)]
pub struct DriverConfig {
pub dma: Dma,
pub intr_flags: EnumSet<IntrFlags>,
}
impl DriverConfig {
pub fn new() -> Self {
Default::default()
}
#[must_use]
pub fn dma(mut self, dma: Dma) -> Self {
self.dma = dma;
self
}
#[must_use]
pub fn intr_flags(mut self, intr_flags: EnumSet<IntrFlags>) -> Self {
self.intr_flags = intr_flags;
self
}
}
impl Default for DriverConfig {
fn default() -> Self {
Self {
dma: Dma::Disabled,
intr_flags: EnumSet::<IntrFlags>::empty(),
}
}
}
/// SPI Device configuration /// SPI Device configuration
#[derive(Copy, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub baudrate: Hertz, pub baudrate: Hertz,
pub data_mode: embedded_hal::spi::Mode, pub data_mode: embedded_hal::spi::Mode,
@ -214,26 +253,31 @@ pub mod config {
self self
} }
#[must_use]
pub fn write_only(mut self, write_only: bool) -> Self { pub fn write_only(mut self, write_only: bool) -> Self {
self.write_only = write_only; self.write_only = write_only;
self self
} }
#[must_use]
pub fn duplex(mut self, duplex: Duplex) -> Self { pub fn duplex(mut self, duplex: Duplex) -> Self {
self.duplex = duplex; self.duplex = duplex;
self self
} }
#[must_use]
pub fn bit_order(mut self, bit_order: BitOrder) -> Self { pub fn bit_order(mut self, bit_order: BitOrder) -> Self {
self.bit_order = bit_order; self.bit_order = bit_order;
self self
} }
#[must_use]
pub fn cs_active_high(mut self) -> Self { pub fn cs_active_high(mut self) -> Self {
self.cs_active_high = true; self.cs_active_high = true;
self self
} }
#[must_use]
pub fn input_delay_ns(mut self, input_delay_ns: i32) -> Self { pub fn input_delay_ns(mut self, input_delay_ns: i32) -> Self {
self.input_delay_ns = input_delay_ns; self.input_delay_ns = input_delay_ns;
self self
@ -476,9 +520,9 @@ impl<'d> SpiDriver<'d> {
sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd, sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd,
sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd, sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd,
sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>, sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>,
dma: Dma, config: &config::DriverConfig,
) -> Result<Self, EspError> { ) -> Result<Self, EspError> {
let max_transfer_size = Self::new_internal(SPI1::device(), sclk, sdo, sdi, dma)?; let max_transfer_size = Self::new_internal(SPI1::device(), sclk, sdo, sdi, config)?;
Ok(Self { Ok(Self {
host: SPI1::device() as _, host: SPI1::device() as _,
@ -493,9 +537,9 @@ impl<'d> SpiDriver<'d> {
sclk: impl Peripheral<P = impl OutputPin> + 'd, sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd, sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>, sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
dma: Dma, config: &config::DriverConfig,
) -> Result<Self, EspError> { ) -> Result<Self, EspError> {
let max_transfer_size = Self::new_internal(SPI::device(), sclk, sdo, sdi, dma)?; let max_transfer_size = Self::new_internal(SPI::device(), sclk, sdo, sdi, config)?;
Ok(Self { Ok(Self {
host: SPI::device() as _, host: SPI::device() as _,
@ -513,14 +557,15 @@ impl<'d> SpiDriver<'d> {
sclk: impl Peripheral<P = impl OutputPin> + 'd, sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd, sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>, sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
dma: Dma, config: &config::DriverConfig,
) -> Result<usize, EspError> { ) -> Result<usize, EspError> {
crate::into_ref!(sclk, sdo); crate::into_ref!(sclk, sdo);
let sdi = sdi.map(|sdi| sdi.into_ref()); let sdi = sdi.map(|sdi| sdi.into_ref());
let max_transfer_sz = dma.max_transfer_size(); let max_transfer_sz = config.dma.max_transfer_size();
let dma_chan: spi_dma_chan_t = dma.into(); let dma_chan: spi_dma_chan_t = config.dma.into();
#[allow(clippy::needless_update)]
#[cfg(not(esp_idf_version = "4.3"))] #[cfg(not(esp_idf_version = "4.3"))]
let bus_config = spi_bus_config_t { let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER, flags: SPICOMMON_BUSFLAG_MASTER,
@ -547,9 +592,11 @@ impl<'d> SpiDriver<'d> {
//data3_io_num: -1, //data3_io_num: -1,
}, },
max_transfer_sz: max_transfer_sz as i32, max_transfer_sz: max_transfer_sz as i32,
intr_flags: IntrFlags::to_native(config.intr_flags) as _,
..Default::default() ..Default::default()
}; };
#[allow(clippy::needless_update)]
#[cfg(esp_idf_version = "4.3")] #[cfg(esp_idf_version = "4.3")]
let bus_config = spi_bus_config_t { let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER, flags: SPICOMMON_BUSFLAG_MASTER,
@ -561,6 +608,7 @@ impl<'d> SpiDriver<'d> {
quadhd_io_num: -1, quadhd_io_num: -1,
max_transfer_sz: max_transfer_sz as i32, max_transfer_sz: max_transfer_sz as i32,
intr_flags: config.intr_flags.into() as _,
..Default::default() ..Default::default()
}; };
@ -594,11 +642,15 @@ impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd, sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd,
sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd, sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd,
sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>, sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>,
dma: Dma,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>, cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
bus_config: &config::DriverConfig,
config: &config::Config, config: &config::Config,
) -> Result<Self, EspError> { ) -> Result<Self, EspError> {
Self::new(SpiDriver::new_spi1(spi, sclk, sdo, sdi, dma)?, cs, config) Self::new(
SpiDriver::new_spi1(spi, sclk, sdo, sdi, bus_config)?,
cs,
config,
)
} }
pub fn new_single<SPI: SpiAnyPins>( pub fn new_single<SPI: SpiAnyPins>(
@ -606,11 +658,11 @@ impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
sclk: impl Peripheral<P = impl OutputPin> + 'd, sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd, sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>, sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
dma: Dma,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>, cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
bus_config: &config::DriverConfig,
config: &config::Config, config: &config::Config,
) -> Result<Self, EspError> { ) -> Result<Self, EspError> {
Self::new(SpiDriver::new(spi, sclk, sdo, sdi, dma)?, cs, config) Self::new(SpiDriver::new(spi, sclk, sdo, sdi, bus_config)?, cs, config)
} }
} }

View File

@ -44,6 +44,7 @@ use core::sync::atomic::{AtomicU8, Ordering};
use crate::delay::NON_BLOCK; use crate::delay::NON_BLOCK;
use crate::gpio::*; use crate::gpio::*;
use crate::interrupt::IntrFlags;
use crate::units::*; use crate::units::*;
use esp_idf_sys::*; use esp_idf_sys::*;
@ -56,7 +57,8 @@ pub type UartConfig = config::Config;
/// UART configuration /// UART configuration
pub mod config { pub mod config {
use crate::units::*; use crate::{interrupt::IntrFlags, units::*};
use enumset::EnumSet;
use esp_idf_sys::*; use esp_idf_sys::*;
/// Number of data bits /// Number of data bits
@ -299,7 +301,7 @@ pub mod config {
} }
/// UART configuration /// UART configuration
#[derive(Debug, Copy, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
pub baudrate: Hertz, pub baudrate: Hertz,
pub data_bits: DataBits, pub data_bits: DataBits,
@ -308,6 +310,7 @@ pub mod config {
pub flow_control: FlowControl, pub flow_control: FlowControl,
pub flow_control_rts_threshold: u8, pub flow_control_rts_threshold: u8,
pub source_clock: SourceClock, pub source_clock: SourceClock,
pub intr_flags: EnumSet<IntrFlags>,
} }
impl Config { impl Config {
@ -383,6 +386,7 @@ pub mod config {
flow_control: FlowControl::None, flow_control: FlowControl::None,
flow_control_rts_threshold: 122, flow_control_rts_threshold: 122,
source_clock: SourceClock::default(), source_clock: SourceClock::default(),
intr_flags: EnumSet::<IntrFlags>::empty(),
} }
} }
} }
@ -934,6 +938,7 @@ fn new_common<UART: Uart>(
}; };
esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?; esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?;
esp!(unsafe { uart_intr_config(UART::port(), IntrFlags::to_native(config.intr_flags) as _) })?;
esp!(unsafe { esp!(unsafe {
uart_set_pin( uart_set_pin(