mirror of
https://github.com/esp-rs/esp-idf-hal.git
synced 2025-09-29 21:31:17 +00:00
Interrupt flags
This commit is contained in:
parent
01d35f3973
commit
ba9cc4246a
@ -29,7 +29,7 @@ fn main() -> Result<()> {
|
||||
|
||||
// 3 seconds white at 10% brightness
|
||||
neopixel(
|
||||
RGB {
|
||||
Rgb {
|
||||
r: 25,
|
||||
g: 25,
|
||||
b: 25,
|
||||
@ -51,7 +51,7 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
struct RGB {
|
||||
struct Rgb {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
@ -61,7 +61,7 @@ fn ns(nanos: u64) -> Duration {
|
||||
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)
|
||||
// G R B
|
||||
// 7 0 7 0 7 0
|
||||
@ -85,7 +85,7 @@ fn neopixel(rgb: RGB, tx: &mut TxRmtDriver) -> Result<()> {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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;
|
||||
g = x;
|
||||
b = 0.0;
|
||||
} else if h >= 60 && h < 120 {
|
||||
} else if (60..120).contains(&h) {
|
||||
r = x;
|
||||
g = c;
|
||||
b = 0.0;
|
||||
} else if h >= 120 && h < 180 {
|
||||
} else if (120..180).contains(&h) {
|
||||
r = 0.0;
|
||||
g = c;
|
||||
b = x;
|
||||
} else if h >= 180 && h < 240 {
|
||||
} else if (180..240).contains(&h) {
|
||||
r = 0.0;
|
||||
g = x;
|
||||
b = c;
|
||||
} else if h >= 240 && h < 300 {
|
||||
} else if (240..300).contains(&h) {
|
||||
r = x;
|
||||
g = 0.0;
|
||||
b = c;
|
||||
@ -121,7 +121,7 @@ fn hsv2rgb(h: u32, s: u32, v: u32) -> Result<RGB> {
|
||||
b = x;
|
||||
}
|
||||
|
||||
Ok(RGB {
|
||||
Ok(Rgb {
|
||||
r: ((r + m) * 255.0) as u8,
|
||||
g: ((g + m) * 255.0) as u8,
|
||||
b: ((b + m) * 255.0) as u8,
|
||||
|
@ -32,7 +32,13 @@ fn main() -> anyhow::Result<()> {
|
||||
|
||||
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 mut device_1 = SpiDeviceDriver::new(&driver, Some(cs_1), &config_1)?;
|
||||
|
@ -52,8 +52,15 @@ fn main() -> anyhow::Result<()> {
|
||||
.baudrate(26.MHz().into())
|
||||
.data_mode(MODE_3);
|
||||
|
||||
let device =
|
||||
SpiDeviceDriver::new_single(spi, sclk, sda, Some(sdi), Dma::Disabled, Some(cs), &config)?;
|
||||
let device = SpiDeviceDriver::new_single(
|
||||
spi,
|
||||
sclk,
|
||||
sda,
|
||||
Some(sdi),
|
||||
Some(cs),
|
||||
&SpiDriverConfig::new(),
|
||||
&config,
|
||||
)?;
|
||||
|
||||
// display interface abstraction from SPI and DC
|
||||
let di = SPIInterfaceNoCS::new(device, dc);
|
||||
|
33
src/can.rs
33
src/can.rs
@ -36,6 +36,7 @@ use esp_idf_sys::*;
|
||||
|
||||
use crate::delay::{BLOCK, NON_BLOCK};
|
||||
use crate::gpio::*;
|
||||
use crate::interrupt::IntrFlags;
|
||||
use crate::peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
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 mod config {
|
||||
use enumset::EnumSet;
|
||||
use esp_idf_sys::*;
|
||||
|
||||
use crate::interrupt::IntrFlags;
|
||||
|
||||
/// CAN timing
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Timing {
|
||||
@ -433,7 +437,7 @@ pub mod config {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub timing: Timing,
|
||||
pub filter: Filter,
|
||||
@ -441,14 +445,19 @@ pub mod config {
|
||||
pub rx_queue_len: u32,
|
||||
pub mode: Mode,
|
||||
pub alerts: Alerts,
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Self {
|
||||
Config {
|
||||
Self {
|
||||
timing: Default::default(),
|
||||
filter: Default::default(),
|
||||
tx_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
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn tx_queue_len(mut self, tx_queue_len: u32) -> Self {
|
||||
self.tx_queue_len = tx_queue_len;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn rx_queue_len(mut self, rx_queue_len: u32) -> Self {
|
||||
self.rx_queue_len = rx_queue_len;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mode(mut self, mode: Mode) -> Self {
|
||||
self.mode = mode;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn alerts(mut self, alerts: Alerts) -> Self {
|
||||
self.alerts = alerts;
|
||||
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,
|
||||
alerts_enabled: config.alerts.into(),
|
||||
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();
|
||||
|
21
src/gpio.rs
21
src/gpio.rs
@ -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 =
|
||||
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();
|
||||
|
||||
#[cfg(all(not(feature = "riscv-ulp-hal"), feature = "alloc"))]
|
||||
fn enable_isr_service() -> Result<(), EspError> {
|
||||
#[cfg(not(feature = "riscv-ulp-hal"))]
|
||||
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;
|
||||
|
||||
if !ISR_SERVICE_ENABLED.load(Ordering::SeqCst) {
|
||||
let _guard = ISR_SERVICE_ENABLED_CS.enter();
|
||||
|
||||
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);
|
||||
}
|
||||
|
31
src/i2c.rs
31
src/i2c.rs
@ -7,6 +7,7 @@ use esp_idf_sys::*;
|
||||
|
||||
use crate::delay::*;
|
||||
use crate::gpio::*;
|
||||
use crate::interrupt::IntrFlags;
|
||||
use crate::peripheral::Peripheral;
|
||||
use crate::units::*;
|
||||
|
||||
@ -36,16 +37,19 @@ pub type I2cSlaveConfig = config::SlaveConfig;
|
||||
|
||||
/// I2C configuration
|
||||
pub mod config {
|
||||
use enumset::EnumSet;
|
||||
|
||||
use super::APBTickType;
|
||||
use crate::units::*;
|
||||
use crate::{interrupt::IntrFlags, units::*};
|
||||
|
||||
/// I2C Master configuration
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub baudrate: Hertz,
|
||||
pub sda_pullup_enabled: bool,
|
||||
pub scl_pullup_enabled: bool,
|
||||
pub timeout: Option<APBTickType>,
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -76,6 +80,12 @@ pub mod config {
|
||||
self.timeout = Some(timeout);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
|
||||
self.intr_flags = flags;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -85,18 +95,20 @@ pub mod config {
|
||||
sda_pullup_enabled: true,
|
||||
scl_pullup_enabled: true,
|
||||
timeout: None,
|
||||
intr_flags: EnumSet::<IntrFlags>::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// I2C Slave configuration
|
||||
#[cfg(not(esp32c2))]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SlaveConfig {
|
||||
pub sda_pullup_enabled: bool,
|
||||
pub scl_pullup_enabled: bool,
|
||||
pub rx_buf_len: usize,
|
||||
pub tx_buf_len: usize,
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
#[cfg(not(esp32c2))]
|
||||
@ -128,6 +140,12 @@ pub mod config {
|
||||
self.tx_buf_len = len;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
|
||||
self.intr_flags = flags;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(esp32c2))]
|
||||
@ -138,6 +156,7 @@ pub mod config {
|
||||
scl_pullup_enabled: true,
|
||||
rx_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,
|
||||
0, // Not used in master mode
|
||||
0, // Not used in master mode
|
||||
0,
|
||||
) // TODO: set flags
|
||||
IntrFlags::to_native(config.intr_flags) as _,
|
||||
)
|
||||
})?;
|
||||
|
||||
if let Some(timeout) = config.timeout {
|
||||
@ -460,7 +479,7 @@ impl<'d> I2cSlaveDriver<'d> {
|
||||
i2c_mode_t_I2C_MODE_SLAVE,
|
||||
config.rx_buf_len,
|
||||
config.tx_buf_len,
|
||||
0, // TODO: set flags
|
||||
IntrFlags::to_native(config.intr_flags) as _,
|
||||
)
|
||||
})?;
|
||||
|
||||
|
@ -1,7 +1,82 @@
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
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();
|
||||
|
||||
/// Returns true if the currently active core is executing an ISR request
|
||||
|
11
src/pcnt.rs
11
src/pcnt.rs
@ -515,6 +515,8 @@ impl Drop for PcntDriver<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
static ISR_ALLOC_FLAGS: core::sync::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool =
|
||||
core::sync::atomic::AtomicBool::new(false);
|
||||
@ -522,6 +524,13 @@ static ISR_SERVICE_ENABLED: core::sync::atomic::AtomicBool =
|
||||
#[cfg(feature = "alloc")]
|
||||
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")]
|
||||
fn enable_isr_service() -> Result<(), EspError> {
|
||||
use core::sync::atomic::Ordering;
|
||||
@ -530,7 +539,7 @@ fn enable_isr_service() -> Result<(), EspError> {
|
||||
let _cs = PCNT_CS.enter();
|
||||
|
||||
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);
|
||||
}
|
||||
|
57
src/rmt.rs
57
src/rmt.rs
@ -64,6 +64,7 @@ use esp_idf_sys::*;
|
||||
|
||||
use crate::gpio::InputPin;
|
||||
use crate::gpio::OutputPin;
|
||||
use crate::interrupt::IntrFlags;
|
||||
use crate::peripheral::Peripheral;
|
||||
use crate::units::Hertz;
|
||||
|
||||
@ -250,10 +251,14 @@ pub type RxRmtConfig = config::ReceiveConfig;
|
||||
///
|
||||
/// ```
|
||||
pub mod config {
|
||||
use enumset::EnumSet;
|
||||
use esp_idf_sys::{EspError, ESP_ERR_INVALID_ARG};
|
||||
|
||||
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`].
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
@ -292,16 +297,19 @@ pub mod config {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn frequency(mut self, hz: Hertz) -> Self {
|
||||
self.frequency = hz;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn carrier_level(mut self, state: PinState) -> Self {
|
||||
self.carrier_level = state;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn duty_percent(mut self, duty: DutyPercent) -> Self {
|
||||
self.duty_percent = duty;
|
||||
self
|
||||
@ -329,6 +337,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// Used when creating a [`Transmit`][crate::rmt::Transmit] instance.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TransmitConfig {
|
||||
pub clock_divider: 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
|
||||
/// channel can continue work even when APB clock is changing.
|
||||
pub aware_dfs: bool,
|
||||
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
impl TransmitConfig {
|
||||
@ -355,38 +366,51 @@ pub mod config {
|
||||
looping: Loop::None,
|
||||
carrier: None,
|
||||
idle: Some(PinState::Low),
|
||||
intr_flags: EnumSet::<IntrFlags>::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn aware_dfs(mut self, enable: bool) -> Self {
|
||||
self.aware_dfs = enable;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
|
||||
self.mem_block_num = mem_block_num;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn clock_divider(mut self, divider: u8) -> Self {
|
||||
self.clock_divider = divider;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn looping(mut self, looping: Loop) -> Self {
|
||||
self.looping = looping;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
|
||||
self.carrier = carrier;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn idle(mut self, idle: Option<PinState>) -> Self {
|
||||
self.idle = idle;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
|
||||
self.intr_flags = flags;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TransmitConfig {
|
||||
@ -397,6 +421,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// Used when creating a [`Receive`][crate::rmt::Receive] instance.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReceiveConfig {
|
||||
pub clock_divider: u8,
|
||||
pub mem_block_num: u8,
|
||||
@ -404,6 +429,7 @@ pub mod config {
|
||||
pub filter_ticks_thresh: u8,
|
||||
pub filter_en: bool,
|
||||
pub carrier: Option<CarrierConfig>,
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
impl ReceiveConfig {
|
||||
@ -411,35 +437,47 @@ pub mod config {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn clock_divider(mut self, divider: u8) -> Self {
|
||||
self.clock_divider = divider;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn mem_block_num(mut self, mem_block_num: u8) -> Self {
|
||||
self.mem_block_num = mem_block_num;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn idle_threshold(mut self, threshold: u16) -> Self {
|
||||
self.idle_threshold = threshold;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn filter_ticks_thresh(mut self, threshold: u8) -> Self {
|
||||
self.filter_ticks_thresh = threshold;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn filter_en(mut self, enable: bool) -> Self {
|
||||
self.filter_en = enable;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn carrier(mut self, carrier: Option<CarrierConfig>) -> Self {
|
||||
self.carrier = carrier;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn intr_flags(mut self, flags: EnumSet<IntrFlags>) -> Self {
|
||||
self.intr_flags = flags;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
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_en: true,
|
||||
carrier: None,
|
||||
intr_flags: EnumSet::<IntrFlags>::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -520,7 +559,11 @@ impl<'d> TxRmtDriver<'d> {
|
||||
|
||||
unsafe {
|
||||
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 {
|
||||
@ -943,7 +986,7 @@ impl<'d> RxRmtDriver<'d> {
|
||||
#[cfg(not(any(esp32, esp32c2)))]
|
||||
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,
|
||||
channel: C::channel(),
|
||||
gpio_num: pin.pin(),
|
||||
@ -968,8 +1011,12 @@ impl<'d> RxRmtDriver<'d> {
|
||||
};
|
||||
|
||||
unsafe {
|
||||
esp!(rmt_config(&config))?;
|
||||
esp!(rmt_driver_install(C::channel(), ring_buf_size * 4, 0))?;
|
||||
esp!(rmt_config(&sys_config))?;
|
||||
esp!(rmt_driver_install(
|
||||
C::channel(),
|
||||
ring_buf_size * 4,
|
||||
IntrFlags::to_native(config.intr_flags) as _
|
||||
))?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
82
src/spi.rs
82
src/spi.rs
@ -45,6 +45,7 @@ use esp_idf_sys::*;
|
||||
|
||||
use crate::delay::{Ets, BLOCK};
|
||||
use crate::gpio::{AnyOutputPin, InputPin, Level, Output, OutputPin, PinDriver};
|
||||
use crate::interrupt::IntrFlags;
|
||||
use crate::peripheral::Peripheral;
|
||||
use crate::task::CriticalSection;
|
||||
|
||||
@ -96,13 +97,17 @@ impl Dma {
|
||||
}
|
||||
}
|
||||
|
||||
pub type SpiDriverConfig = config::DriverConfig;
|
||||
pub type SpiConfig = config::Config;
|
||||
|
||||
/// SPI configuration
|
||||
pub mod config {
|
||||
use crate::units::*;
|
||||
use crate::{interrupt::IntrFlags, units::*};
|
||||
use enumset::EnumSet;
|
||||
use esp_idf_sys::*;
|
||||
|
||||
use super::Dma;
|
||||
|
||||
pub struct V02Type<T>(pub T);
|
||||
|
||||
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
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Duplex {
|
||||
/// Full duplex is the default
|
||||
Full,
|
||||
@ -158,7 +163,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// Most significant bit first (default)
|
||||
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
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub baudrate: Hertz,
|
||||
pub data_mode: embedded_hal::spi::Mode,
|
||||
@ -214,26 +253,31 @@ pub mod config {
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn write_only(mut self, write_only: bool) -> Self {
|
||||
self.write_only = write_only;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn duplex(mut self, duplex: Duplex) -> Self {
|
||||
self.duplex = duplex;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn bit_order(mut self, bit_order: BitOrder) -> Self {
|
||||
self.bit_order = bit_order;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn cs_active_high(mut self) -> Self {
|
||||
self.cs_active_high = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn input_delay_ns(mut self, input_delay_ns: i32) -> Self {
|
||||
self.input_delay_ns = input_delay_ns;
|
||||
self
|
||||
@ -476,9 +520,9 @@ impl<'d> SpiDriver<'d> {
|
||||
sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd,
|
||||
sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd,
|
||||
sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>,
|
||||
dma: Dma,
|
||||
config: &config::DriverConfig,
|
||||
) -> 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 {
|
||||
host: SPI1::device() as _,
|
||||
@ -493,9 +537,9 @@ impl<'d> SpiDriver<'d> {
|
||||
sclk: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdo: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
|
||||
dma: Dma,
|
||||
config: &config::DriverConfig,
|
||||
) -> 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 {
|
||||
host: SPI::device() as _,
|
||||
@ -513,14 +557,15 @@ impl<'d> SpiDriver<'d> {
|
||||
sclk: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdo: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
|
||||
dma: Dma,
|
||||
config: &config::DriverConfig,
|
||||
) -> Result<usize, EspError> {
|
||||
crate::into_ref!(sclk, sdo);
|
||||
let sdi = sdi.map(|sdi| sdi.into_ref());
|
||||
|
||||
let max_transfer_sz = dma.max_transfer_size();
|
||||
let dma_chan: spi_dma_chan_t = dma.into();
|
||||
let max_transfer_sz = config.dma.max_transfer_size();
|
||||
let dma_chan: spi_dma_chan_t = config.dma.into();
|
||||
|
||||
#[allow(clippy::needless_update)]
|
||||
#[cfg(not(esp_idf_version = "4.3"))]
|
||||
let bus_config = spi_bus_config_t {
|
||||
flags: SPICOMMON_BUSFLAG_MASTER,
|
||||
@ -547,9 +592,11 @@ impl<'d> SpiDriver<'d> {
|
||||
//data3_io_num: -1,
|
||||
},
|
||||
max_transfer_sz: max_transfer_sz as i32,
|
||||
intr_flags: IntrFlags::to_native(config.intr_flags) as _,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
#[allow(clippy::needless_update)]
|
||||
#[cfg(esp_idf_version = "4.3")]
|
||||
let bus_config = spi_bus_config_t {
|
||||
flags: SPICOMMON_BUSFLAG_MASTER,
|
||||
@ -561,6 +608,7 @@ impl<'d> SpiDriver<'d> {
|
||||
quadhd_io_num: -1,
|
||||
|
||||
max_transfer_sz: max_transfer_sz as i32,
|
||||
intr_flags: config.intr_flags.into() as _,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -594,11 +642,15 @@ impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
|
||||
sclk: impl Peripheral<P = crate::gpio::Gpio6> + 'd,
|
||||
sdo: impl Peripheral<P = crate::gpio::Gpio7> + 'd,
|
||||
sdi: Option<impl Peripheral<P = crate::gpio::Gpio8> + 'd>,
|
||||
dma: Dma,
|
||||
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
|
||||
bus_config: &config::DriverConfig,
|
||||
config: &config::Config,
|
||||
) -> 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>(
|
||||
@ -606,11 +658,11 @@ impl<'d> SpiDeviceDriver<'d, SpiDriver<'d>> {
|
||||
sclk: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdo: impl Peripheral<P = impl OutputPin> + 'd,
|
||||
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
|
||||
dma: Dma,
|
||||
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
|
||||
bus_config: &config::DriverConfig,
|
||||
config: &config::Config,
|
||||
) -> 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use crate::delay::NON_BLOCK;
|
||||
use crate::gpio::*;
|
||||
use crate::interrupt::IntrFlags;
|
||||
use crate::units::*;
|
||||
|
||||
use esp_idf_sys::*;
|
||||
@ -56,7 +57,8 @@ pub type UartConfig = config::Config;
|
||||
|
||||
/// UART configuration
|
||||
pub mod config {
|
||||
use crate::units::*;
|
||||
use crate::{interrupt::IntrFlags, units::*};
|
||||
use enumset::EnumSet;
|
||||
use esp_idf_sys::*;
|
||||
|
||||
/// Number of data bits
|
||||
@ -299,7 +301,7 @@ pub mod config {
|
||||
}
|
||||
|
||||
/// UART configuration
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub baudrate: Hertz,
|
||||
pub data_bits: DataBits,
|
||||
@ -308,6 +310,7 @@ pub mod config {
|
||||
pub flow_control: FlowControl,
|
||||
pub flow_control_rts_threshold: u8,
|
||||
pub source_clock: SourceClock,
|
||||
pub intr_flags: EnumSet<IntrFlags>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -383,6 +386,7 @@ pub mod config {
|
||||
flow_control: FlowControl::None,
|
||||
flow_control_rts_threshold: 122,
|
||||
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_intr_config(UART::port(), IntrFlags::to_native(config.intr_flags) as _) })?;
|
||||
|
||||
esp!(unsafe {
|
||||
uart_set_pin(
|
||||
|
Loading…
x
Reference in New Issue
Block a user