PeripheralRef support; critical-section support

This commit is contained in:
Ivan Markov 2022-08-20 11:39:55 +00:00
parent 812e188223
commit 2ace88dc58
15 changed files with 2079 additions and 2017 deletions

View File

@ -6,49 +6,47 @@ use esp_idf_sys::*;
#[cfg(feature = "riscv-ulp-hal")]
use crate::riscv_ulp_hal::sys::*;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::gpio::ADCPin;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::peripheral::{Peripheral, PeripheralRef};
#[cfg(not(feature = "riscv-ulp-hal"))]
pub type AdcConfig = config::Config;
pub trait Adc: Send {
fn unit() -> adc_unit_t;
}
pub trait Analog<ADC: Adc>: Send {
pub trait Attenuation<ADC: Adc>: Send {
fn attenuation() -> adc_atten_t;
}
pub struct Atten0dB<ADC: Adc> {
_adc: PhantomData<ADC>,
}
pub struct Atten0dB<ADC: Adc>(PhantomData<ADC>);
pub struct Atten2p5dB<ADC: Adc>(PhantomData<ADC>);
pub struct Atten6dB<ADC: Adc>(PhantomData<ADC>);
pub struct Atten11dB<ADC: Adc>(PhantomData<ADC>);
pub struct Atten2p5dB<ADC: Adc> {
_adc: PhantomData<ADC>,
}
pub struct Atten6dB<ADC: Adc> {
_adc: PhantomData<ADC>,
}
pub struct Atten11dB<ADC: Adc> {
_adc: PhantomData<ADC>,
}
impl<ADC: Adc> Analog<ADC> for Atten0dB<ADC> {
impl<ADC: Adc> Attenuation<ADC> for Atten0dB<ADC> {
fn attenuation() -> adc_atten_t {
adc_atten_t_ADC_ATTEN_DB_0
}
}
impl<ADC: Adc> Analog<ADC> for Atten2p5dB<ADC> {
impl<ADC: Adc> Attenuation<ADC> for Atten2p5dB<ADC> {
fn attenuation() -> adc_atten_t {
adc_atten_t_ADC_ATTEN_DB_2_5
}
}
impl<ADC: Adc> Analog<ADC> for Atten6dB<ADC> {
impl<ADC: Adc> Attenuation<ADC> for Atten6dB<ADC> {
fn attenuation() -> adc_atten_t {
adc_atten_t_ADC_ATTEN_DB_6
}
}
impl<ADC: Adc> Analog<ADC> for Atten11dB<ADC> {
impl<ADC: Adc> Attenuation<ADC> for Atten11dB<ADC> {
fn attenuation() -> adc_atten_t {
adc_atten_t_ADC_ATTEN_DB_11
}
@ -131,8 +129,57 @@ pub mod config {
}
#[cfg(not(feature = "riscv-ulp-hal"))]
pub struct PoweredAdc<ADC: Adc> {
adc: ADC,
pub struct AdcChannelDriver<'d, T: ADCPin, ATTEN> {
pin: PeripheralRef<'d, T>,
_atten: PhantomData<ATTEN>,
}
#[cfg(not(feature = "riscv-ulp-hal"))]
impl<'d, T: ADCPin, ATTEN> AdcChannelDriver<'d, T, ATTEN>
where
ATTEN: Attenuation<T::Adc>,
{
#[inline]
pub fn new(
pin: impl Peripheral<P = T> + 'd,
) -> Result<AdcChannelDriver<'d, T, ATTEN>, EspError> {
crate::into_ref!(pin);
unsafe {
crate::gpio::rtc_reset_pin(pin.pin())?;
}
if T::Adc::unit() == adc_unit_t_ADC_UNIT_1 {
esp!(unsafe { adc1_config_channel_atten(pin.adc_channel(), ATTEN::attenuation()) })?;
} else {
esp!(unsafe { adc2_config_channel_atten(pin.adc_channel(), ATTEN::attenuation()) })?;
}
Ok(Self {
pin,
_atten: PhantomData,
})
}
fn pin(&mut self) -> &mut PeripheralRef<'d, T> {
&mut self.pin
}
}
#[cfg(not(feature = "riscv-ulp-hal"))]
impl<'d, T: ADCPin, ATTEN> embedded_hal_0_2::adc::Channel<ATTEN>
for AdcChannelDriver<'d, T, ATTEN>
{
type ID = u8;
fn channel() -> Self::ID {
T::CHANNEL as _
}
}
#[cfg(not(feature = "riscv-ulp-hal"))]
pub struct AdcDriver<'d, ADC: Adc> {
_adc: PeripheralRef<'d, ADC>,
resolution: config::Resolution,
#[cfg(any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled))]
cal_characteristics:
@ -140,10 +187,10 @@ pub struct PoweredAdc<ADC: Adc> {
}
#[cfg(not(feature = "riscv-ulp-hal"))]
unsafe impl<ADC: Adc> Send for PoweredAdc<ADC> {}
unsafe impl<'d, ADC: Adc> Send for AdcDriver<'d, ADC> {}
#[cfg(not(feature = "riscv-ulp-hal"))]
impl<ADC: Adc> PoweredAdc<ADC> {
impl<'d, ADC: Adc> AdcDriver<'d, ADC> {
#[cfg(all(
esp32,
any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
@ -169,7 +216,12 @@ impl<ADC: Adc> PoweredAdc<ADC> {
#[cfg(esp32s2)]
const MAX_READING: u32 = 8191;
pub fn new(adc: ADC, config: config::Config) -> Result<Self, EspError> {
pub fn new(
adc: impl Peripheral<P = ADC> + 'd,
config: &config::Config,
) -> Result<Self, EspError> {
crate::into_ref!(adc);
#[cfg(any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled))]
if config.calibration {
esp!(unsafe { esp_adc_cal_check_efuse(Self::CALIBRATION_SCHEME) })?;
@ -180,7 +232,7 @@ impl<ADC: Adc> PoweredAdc<ADC> {
}
Ok(Self {
adc,
_adc: adc,
resolution: config.resolution,
#[cfg(any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled))]
cal_characteristics: if config.calibration {
@ -191,8 +243,44 @@ impl<ADC: Adc> PoweredAdc<ADC> {
})
}
pub fn release(self) -> ADC {
self.adc
pub fn read<'c, T, ATTEN>(
&mut self,
pin: &mut AdcChannelDriver<'c, T, ATTEN>,
) -> Result<u16, EspError>
where
T: ADCPin,
ATTEN: Attenuation<T::Adc>,
{
self.read_internal(ADC::unit(), pin.pin().adc_channel(), ATTEN::attenuation())
}
#[cfg(all(esp32, esp_idf_version_major = "4"))]
pub fn read_hall(
&mut self,
_hall_sensor: &mut crate::hall::HallSensor,
) -> Result<u16, EspError> {
let measurement = unsafe { hall_sensor_read() };
Ok(self.raw_to_voltage(measurement, adc_atten_t_ADC_ATTEN_DB_0)?)
}
fn read_internal(
&mut self,
unit: adc_unit_t,
channel: adc_channel_t,
atten: adc_atten_t,
) -> Result<u16, EspError> {
let mut measurement = 0_i32;
if unit == adc_unit_t_ADC_UNIT_1 {
measurement = unsafe { adc1_get_raw(channel) };
} else {
esp!(unsafe {
adc2_get_raw(channel, self.resolution.into(), &mut measurement as *mut _)
})?;
};
self.raw_to_voltage(measurement, atten)
}
fn raw_to_voltage(
@ -275,81 +363,49 @@ impl<ADC: Adc> PoweredAdc<ADC> {
Ok(None)
}
}
fn read(
&mut self,
unit: adc_unit_t,
channel: adc_channel_t,
atten: adc_atten_t,
) -> nb::Result<u16, EspError> {
let mut measurement = 0_i32;
if unit == adc_unit_t_ADC_UNIT_1 {
measurement = unsafe { adc1_get_raw(channel) };
} else {
let res = unsafe {
adc2_get_raw(channel, self.resolution.into(), &mut measurement as *mut _)
};
if res == ESP_ERR_INVALID_STATE as i32 {
return Err(nb::Error::WouldBlock);
} else if res < 0 {
return Err(nb::Error::Other(EspError::from(res).unwrap()));
}
};
Ok(self.raw_to_voltage(measurement, atten)?)
}
#[cfg(all(esp32, esp_idf_version_major = "4"))]
fn read_hall(&mut self) -> nb::Result<u16, EspError> {
let measurement = unsafe { hall_sensor_read() };
Ok(self.raw_to_voltage(measurement, adc_atten_t_ADC_ATTEN_DB_0)?)
}
}
#[cfg(not(feature = "riscv-ulp-hal"))]
impl<ADC, AN, PIN> embedded_hal_0_2::adc::OneShot<AN, u16, PIN> for PoweredAdc<ADC>
impl<'d, ADC, ATTEN, PIN> embedded_hal_0_2::adc::OneShot<ATTEN, u16, PIN> for AdcDriver<'d, ADC>
where
ADC: Adc,
AN: Analog<ADC>,
PIN: embedded_hal_0_2::adc::Channel<AN, ID = u8>,
ATTEN: Attenuation<ADC>,
PIN: embedded_hal_0_2::adc::Channel<ATTEN, ID = u8>,
{
type Error = EspError;
fn read(&mut self, _pin: &mut PIN) -> nb::Result<u16, Self::Error> {
self.read(
self.read_internal(
ADC::unit(),
PIN::channel() as adc_channel_t,
AN::attenuation(),
ATTEN::attenuation(),
)
.map_err(to_nb_err)
}
}
#[cfg(all(esp32, esp_idf_version_major = "4", not(feature = "riscv-ulp-hal")))]
impl embedded_hal_0_2::adc::OneShot<ADC1, u16, crate::hall::HallSensor> for PoweredAdc<ADC1> {
impl<'d> embedded_hal_0_2::adc::OneShot<ADC1, u16, crate::hall::HallSensor>
for AdcDriver<'d, ADC1>
{
type Error = EspError;
fn read(&mut self, _hall_sensor: &mut crate::hall::HallSensor) -> nb::Result<u16, Self::Error> {
self.read_hall()
fn read(&mut self, hall_sensor: &mut crate::hall::HallSensor) -> nb::Result<u16, Self::Error> {
AdcDriver::read_hall(self, hall_sensor).map_err(to_nb_err)
}
}
fn to_nb_err(err: EspError) -> nb::Error<EspError> {
if err.code() == ESP_ERR_INVALID_STATE as i32 {
nb::Error::WouldBlock
} else {
nb::Error::Other(err)
}
}
macro_rules! impl_adc {
($adc:ident: $unit:expr) => {
pub struct $adc(::core::marker::PhantomData<*const ()>);
impl $adc {
/// # Safety
///
/// Care should be taken not to instnatiate this ADC instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
$adc(::core::marker::PhantomData)
}
}
unsafe impl Send for $adc {}
crate::impl_peripheral!($adc);
impl Adc for $adc {
#[inline(always)]

View File

@ -22,7 +22,7 @@
//!
//! let timing = can::config::Timing::B500K;
//! let config = can::config::Config::new().filter(filter).timing(timing);
//! let mut can = can::CanBus::new(peripherals.can, pins.gpio5, pins.gpio4, config).unwrap();
//! let mut can = can::CanDriver::new(peripherals.can, pins.gpio5, pins.gpio4, &config).unwrap();
//!
//! let tx_frame = can::Frame::new(StandardId::new(0x042).unwrap(), &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
//! nb::block!(can.transmit(&tx_frame)).unwrap();
@ -32,12 +32,11 @@
//! }
//! ```
use core::marker::PhantomData;
use esp_idf_sys::*;
use crate::delay::portMAX_DELAY;
use crate::gpio::*;
use crate::peripheral::{Peripheral, PeripheralRef};
crate::embedded_hal_error!(
CanError,
@ -234,16 +233,19 @@ pub mod config {
}
/// CAN abstraction
pub struct CanBus<TX: OutputPin, RX: InputPin> {
can: CAN,
tx: TX,
rx: RX,
}
pub struct CanDriver<'d>(PeripheralRef<'d, CAN>);
unsafe impl<TX: OutputPin, RX: InputPin> Send for CanBus<TX, RX> {}
unsafe impl<'d> Send for CanDriver<'d> {}
impl<'d> CanDriver<'d> {
pub fn new(
can: impl Peripheral<P = CAN> + 'd,
tx: impl Peripheral<P = impl OutputPin> + 'd,
rx: impl Peripheral<P = impl OutputPin> + 'd,
config: &config::Config,
) -> Result<Self, EspError> {
crate::into_ref!(can, tx, rx);
impl<TX: OutputPin, RX: InputPin> CanBus<TX, RX> {
pub fn new(can: CAN, tx: TX, rx: RX, config: config::Config) -> Result<Self, EspError> {
let general_config = twai_general_config_t {
mode: twai_mode_t_TWAI_MODE_NORMAL,
tx_io: tx.pin(),
@ -276,14 +278,7 @@ impl<TX: OutputPin, RX: InputPin> CanBus<TX, RX> {
esp!(unsafe { twai_driver_install(&general_config, &timing_config, &filter_config) })?;
esp!(unsafe { twai_start() })?;
Ok(Self { can, tx, rx })
}
pub fn release(self) -> Result<(CAN, TX, RX), EspError> {
esp!(unsafe { twai_stop() })?;
esp!(unsafe { twai_driver_uninstall() })?;
Ok((self.can, self.tx, self.rx))
Ok(Self(can))
}
fn transmit_internal(&mut self, frame: &Frame, delay: TickType_t) -> Result<(), EspError> {
@ -302,7 +297,14 @@ impl<TX: OutputPin, RX: InputPin> CanBus<TX, RX> {
}
}
impl<TX: OutputPin, RX: InputPin> embedded_hal_0_2::blocking::can::Can for CanBus<TX, RX> {
impl<'d> Drop for CanDriver<'d> {
fn drop(&mut self) {
esp!(unsafe { twai_stop() }).unwrap();
esp!(unsafe { twai_driver_uninstall() }).unwrap();
}
}
impl<'d> embedded_hal_0_2::blocking::can::Can for CanDriver<'d> {
type Frame = Frame;
type Error = Can02Error;
@ -317,7 +319,7 @@ impl<TX: OutputPin, RX: InputPin> embedded_hal_0_2::blocking::can::Can for CanBu
}
}
impl<TX: OutputPin, RX: InputPin> embedded_hal::can::blocking::Can for CanBus<TX, RX> {
impl<'d> embedded_hal::can::blocking::Can for CanDriver<'d> {
type Frame = Frame;
type Error = CanError;
@ -332,7 +334,7 @@ impl<TX: OutputPin, RX: InputPin> embedded_hal::can::blocking::Can for CanBus<TX
}
}
impl<TX: OutputPin, RX: InputPin> embedded_hal_0_2::can::nb::Can for CanBus<TX, RX> {
impl<'d> embedded_hal_0_2::can::nb::Can for CanDriver<'d> {
type Frame = Frame;
type Error = Can02Error;
@ -354,7 +356,7 @@ impl<TX: OutputPin, RX: InputPin> embedded_hal_0_2::can::nb::Can for CanBus<TX,
}
}
impl<TX: OutputPin, RX: InputPin> embedded_hal::can::nb::Can for CanBus<TX, RX> {
impl<'d> embedded_hal::can::nb::Can for CanDriver<'d> {
type Frame = Frame;
type Error = CanError;
@ -581,15 +583,4 @@ impl embedded_hal::can::Frame for Frame {
}
}
pub struct CAN(PhantomData<*const ()>);
impl CAN {
/// # Safety
///
/// Care should be taken not to instnatiate this CAN instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
CAN(PhantomData)
}
}
unsafe impl Send for CAN {}
crate::impl_peripheral!(CAN);

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,9 @@
use core::marker::PhantomData;
use crate::adc;
pub struct HallSensor(PhantomData<*const ()>);
impl HallSensor {
/// # Safety
///
/// Care should be taken not to instnatiate this Hall Sensor instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
HallSensor(PhantomData)
}
}
unsafe impl Send for HallSensor {}
impl embedded_hal_0_2::adc::Channel<adc::ADC1> for HallSensor {
type ID = ();
fn channel() -> Self::ID {}
}
crate::impl_peripheral!(HallSensor);

View File

@ -1,8 +1,13 @@
use core::marker::PhantomData;
use embedded_hal::i2c::{ErrorKind, NoAcknowledgeSource};
use esp_idf_sys::*;
use crate::{delay::*, gpio::*, units::*};
use crate::delay::*;
use crate::gpio::*;
use crate::peripheral::{Peripheral, PeripheralRef};
use crate::units::*;
crate::embedded_hal_error!(
I2cError,
@ -10,16 +15,6 @@ crate::embedded_hal_error!(
embedded_hal::i2c::ErrorKind
);
pub struct MasterPins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
pub sda: SDA,
pub scl: SCL,
}
pub struct SlavePins<SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> {
pub sda: SDA,
pub scl: SCL,
}
/// I2C configuration
pub mod config {
use crate::units::*;
@ -138,59 +133,36 @@ pub trait I2c: Send {
fn port() -> i2c_port_t;
}
unsafe impl<I2C: I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> Send
for Master<I2C, SDA, SCL>
{
}
pub struct Master<I2C, SDA, SCL>
pub struct I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
i2c: I2C,
pins: MasterPins<SDA, SCL>,
_i2c: PeripheralRef<'d, I2C>,
timeout: TickType_t,
}
pub struct Slave<I2C, SDA, SCL>
impl<'d, I2C> I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
i2c: I2C,
pins: SlavePins<SDA, SCL>,
timeout: TickType_t,
}
unsafe impl<I2C: I2c, SDA: OutputPin + InputPin, SCL: OutputPin + InputPin> Send
for Slave<I2C, SDA, SCL>
{
}
impl<I2C, SDA, SCL> Master<I2C, SDA, SCL>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
pub fn new(
i2c: I2C,
pins: MasterPins<SDA, SCL>,
config: config::MasterConfig,
) -> Result<Master<I2C, SDA, SCL>, EspError> {
i2c: impl Peripheral<P = I2C> + 'd,
sda: impl Peripheral<P = impl InputPin + OutputPin> + 'd,
scl: impl Peripheral<P = impl InputPin + OutputPin> + 'd,
config: &config::MasterConfig,
) -> Result<I2cMasterDriver<'d, I2C>, EspError> {
// i2c_config_t documentation says that clock speed must be no higher than 1 MHz
if config.baudrate > 1.MHz().into() {
return Err(EspError::from(ESP_ERR_INVALID_ARG as i32).unwrap());
}
crate::into_ref!(i2c, sda, scl);
let sys_config = i2c_config_t {
mode: i2c_mode_t_I2C_MODE_MASTER,
sda_io_num: pins.sda.pin(),
sda_io_num: sda.pin(),
sda_pullup_en: config.sda_pullup_enabled,
scl_io_num: pins.scl.pin(),
scl_io_num: scl.pin(),
scl_pullup_en: config.scl_pullup_enabled,
__bindgen_anon_1: i2c_config_t__bindgen_ty_1 {
master: i2c_config_t__bindgen_ty_1__bindgen_ty_1 {
@ -212,22 +184,12 @@ where
) // TODO: set flags
})?;
Ok(Master {
i2c,
pins,
Ok(I2cMasterDriver {
_i2c: i2c,
timeout: TickType::from(config.timeout).0,
})
}
pub fn release(self) -> Result<(I2C, MasterPins<SDA, SCL>), EspError> {
esp!(unsafe { i2c_driver_delete(I2C::port()) })?;
//self.pins.sda.reset()?;
//self.pins.scl.reset()?;
Ok((self.i2c, self.pins))
}
fn cmd_begin(
&mut self,
command_link: &CommandLink,
@ -250,11 +212,17 @@ where
}
}
impl<I2C, SDA, SCL> embedded_hal_0_2::blocking::i2c::Read for Master<I2C, SDA, SCL>
impl<'d, I2C: I2c> Drop for I2cMasterDriver<'d, I2C> {
fn drop(&mut self) {
esp!(unsafe { i2c_driver_delete(I2C::port()) }).unwrap();
}
}
unsafe impl<'d, I2C: I2c> Send for I2cMasterDriver<'d, I2C> {}
impl<'d, I2C> embedded_hal_0_2::blocking::i2c::Read for I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
type Error = I2cError;
@ -263,11 +231,9 @@ where
}
}
impl<I2C, SDA, SCL> embedded_hal_0_2::blocking::i2c::Write for Master<I2C, SDA, SCL>
impl<'d, I2C> embedded_hal_0_2::blocking::i2c::Write for I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
type Error = I2cError;
@ -276,11 +242,9 @@ where
}
}
impl<I2C, SDA, SCL> embedded_hal_0_2::blocking::i2c::WriteRead for Master<I2C, SDA, SCL>
impl<'d, I2C> embedded_hal_0_2::blocking::i2c::WriteRead for I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
type Error = I2cError;
@ -289,21 +253,17 @@ where
}
}
impl<I2C, SDA, SCL> embedded_hal::i2c::ErrorType for Master<I2C, SDA, SCL>
impl<'d, I2C> embedded_hal::i2c::ErrorType for I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
type Error = I2cError;
}
impl<I2C, SDA, SCL> embedded_hal::i2c::blocking::I2c<embedded_hal::i2c::SevenBitAddress>
for Master<I2C, SDA, SCL>
impl<'d, I2C> embedded_hal::i2c::blocking::I2c<embedded_hal::i2c::SevenBitAddress>
for I2cMasterDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
let mut command_link = CommandLink::new().map_err(I2cError::other)?;
@ -455,24 +415,35 @@ where
}
}
impl<I2C, SDA, SCL> Slave<I2C, SDA, SCL>
pub struct I2cSlaveDriver<'d, I2C>
where
I2C: I2c,
{
_i2c: PeripheralRef<'d, I2C>,
timeout: TickType_t,
}
unsafe impl<'d, I2C: I2c> Send for I2cSlaveDriver<'d, I2C> {}
impl<'d, I2C> I2cSlaveDriver<'d, I2C>
where
I2C: I2c,
SDA: OutputPin + InputPin,
SCL: OutputPin + InputPin,
{
pub fn new(
i2c: I2C,
pins: SlavePins<SDA, SCL>,
i2c: impl Peripheral<P = I2C> + 'd,
sda: impl Peripheral<P = impl InputPin + OutputPin> + 'd,
scl: impl Peripheral<P = impl InputPin + OutputPin> + 'd,
slave_addr: u8,
config: config::SlaveConfig,
config: &config::SlaveConfig,
) -> Result<Self, EspError> {
crate::into_ref!(i2c, sda, scl);
#[cfg(any(esp_idf_version = "4.4", esp_idf_version_major = "5"))]
let sys_config = i2c_config_t {
mode: i2c_mode_t_I2C_MODE_SLAVE,
sda_io_num: pins.sda.pin(),
sda_io_num: sda.pin(),
sda_pullup_en: config.sda_pullup_enabled,
scl_io_num: pins.scl.pin(),
scl_io_num: scl.pin(),
scl_pullup_en: config.scl_pullup_enabled,
__bindgen_anon_1: i2c_config_t__bindgen_ty_1 {
slave: i2c_config_t__bindgen_ty_1__bindgen_ty_2 {
@ -513,21 +484,11 @@ where
})?;
Ok(Self {
i2c,
pins,
_i2c: i2c,
timeout: TickType::from(config.timeout).0,
})
}
pub fn release(self) -> Result<(I2C, SlavePins<SDA, SCL>), EspError> {
esp!(unsafe { i2c_driver_delete(I2C::port()) })?;
//self.pins.sda.reset()?;
//self.pins.scl.reset()?;
Ok((self.i2c, self.pins))
}
pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, EspError> {
let n = unsafe {
i2c_slave_read_buffer(
@ -629,18 +590,7 @@ impl<'buffers> Drop for CommandLink<'buffers> {
macro_rules! impl_i2c {
($i2c:ident: $port:expr) => {
pub struct $i2c(::core::marker::PhantomData<*const ()>);
impl $i2c {
/// # Safety
///
/// Care should be taken not to instnatiate this I2C instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
$i2c(::core::marker::PhantomData)
}
}
unsafe impl Send for $i2c {}
crate::impl_peripheral!($i2c);
impl I2c for $i2c {
#[inline(always)]
@ -652,6 +602,5 @@ macro_rules! impl_i2c {
}
impl_i2c!(I2C0: 0);
#[cfg(not(esp32c3))]
impl_i2c!(I2C1: 1);

View File

@ -16,24 +16,21 @@
//! use esp_idf_hal::prelude::*;
//!
//! let peripherals = Peripherals::take().unwrap();
//! let config = TimerConfig::default().frequency(25.kHz().into());
//! let timer = Timer::new(peripherals.ledc.timer0, &config)?;
//! let channel = Channel::new(peripherals.ledc.channel0, &timer, peripherals.pins.gpio1)?;
//! let driver = LedcDriver::new(peripherals.ledc.channel0, peripherals.ledc.timer0, peripherals.pins.gpio1, &TimerConfig::default().frequency(25.kHz().into()))?;
//!
//! let max_duty = channel.get_max_duty()?;
//! channel.set_duty(max_duty * 3 / 4);
//! let max_duty = driver.get_max_duty()?;
//! driver.set_duty(max_duty * 3 / 4);
//! ```
//!
//! See the `examples/` folder of this repository for more.
use core::borrow::Borrow;
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
use esp_idf_sys::*;
use crate::cs::CriticalSection;
use crate::gpio::OutputPin;
use crate::peripheral::{Peripheral, PeripheralRef};
pub use chip::*;
@ -51,6 +48,7 @@ pub mod config {
pub use chip::Resolution;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TimerConfig {
pub frequency: Hertz,
pub resolution: Resolution,
@ -88,16 +86,28 @@ pub mod config {
}
}
/// LED Control timer abstraction
pub struct Timer<T: HwTimer> {
instance: T,
/// LED Control driver
pub struct LedcDriver<'d, C: LedcChannel, T: LedcTimer> {
_channel: PeripheralRef<'d, C>,
_timer: PeripheralRef<'d, T>,
speed_mode: ledc_mode_t,
max_duty: Duty,
duty: Duty,
}
impl<T: HwTimer> Timer<T> {
/// Creates a new LED Control timer abstraction
pub fn new(instance: T, config: &config::TimerConfig) -> Result<Self, EspError> {
// TODO: Stop channel when the instance gets dropped. It seems that we can't
// have both at the same time: a method for releasing its hardware resources
// and implementing Drop.
impl<'d, C: LedcChannel, T: LedcTimer> LedcDriver<'d, C, T> {
/// Creates a new LED Control driver
pub fn new(
channel: impl Peripheral<P = C> + 'd,
timer: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl OutputPin> + 'd,
config: &config::TimerConfig,
) -> Result<Self, EspError> {
crate::into_ref!(channel, timer, pin);
let timer_config = ledc_timer_config_t {
speed_mode: config.speed_mode,
timer_num: T::timer(),
@ -114,58 +124,12 @@ impl<T: HwTimer> Timer<T> {
// SAFETY: We own the instance and therefor are safe to configure it.
esp!(unsafe { ledc_timer_config(&timer_config) })?;
Ok(Timer {
instance,
speed_mode: config.speed_mode,
max_duty: config.resolution.max_duty(),
})
}
/// Pauses the timer. Operation can be resumed with
/// [`resume()`](Timer::resume()).
pub fn pause(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_pause(self.speed_mode, T::timer()) })?;
Ok(())
}
/// Stops the timer and releases its hardware resource
pub fn release(mut self) -> Result<T, EspError> {
self.reset()?;
Ok(self.instance)
}
fn reset(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_rst(self.speed_mode, T::timer()) })?;
Ok(())
}
/// Resumes the operation of a previously paused timer
pub fn resume(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_resume(self.speed_mode, T::timer()) })?;
Ok(())
}
}
/// LED Control output channel abstraction
pub struct Channel<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> {
instance: C,
_hw_timer: PhantomData<H>,
timer: T,
pin: P,
duty: Duty,
}
// TODO: Stop channel when the instance gets dropped. It seems that we can't
// have both at the same time: a method for releasing its hardware resources
// and implementing Drop.
impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> Channel<C, H, T, P> {
/// Creates a new LED Control output channel abstraction
pub fn new(instance: C, timer: T, pin: P) -> Result<Self, EspError> {
let duty = 0;
let channel_config = ledc_channel_config_t {
speed_mode: timer.borrow().speed_mode,
speed_mode: config.speed_mode,
channel: C::channel(),
timer_sel: H::timer(),
timer_sel: T::timer(),
intr_type: ledc_intr_type_t_LEDC_INTR_DISABLE,
gpio_num: pin.pin(),
duty: duty as u32,
@ -192,28 +156,21 @@ impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> Channel<C, H,
// it.
esp!(unsafe { ledc_channel_config(&channel_config) })?;
Ok(Channel {
instance,
_hw_timer: PhantomData,
timer,
pin,
Ok(LedcDriver {
_channel: channel,
_timer: timer,
duty,
speed_mode: config.speed_mode,
max_duty: config.resolution.max_duty(),
})
}
/// Stops the output channel and releases its hardware resource and GPIO
/// pin
pub fn release(mut self) -> Result<(C, P), EspError> {
self.stop()?;
Ok((self.instance, self.pin))
}
pub fn get_duty(&self) -> Duty {
self.duty
}
pub fn get_max_duty(&self) -> Duty {
self.timer.borrow().max_duty
self.max_duty
}
pub fn disable(&mut self) -> Result<(), EspError> {
@ -233,21 +190,38 @@ impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> Channel<C, H,
// TODO: Why does calling self.get_max_duty() result in the compiler
// error 'expected `u32`, found enum `Result`' when our method returns
// Duty?
let clamped = duty.min(self.timer.borrow().max_duty);
let clamped = duty.min(self.max_duty);
self.duty = clamped;
self.update_duty(clamped)?;
Ok(())
}
/// Pauses the timer. Operation can be resumed with [`resume_timer()`].
pub fn pause_timer(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_pause(self.speed_mode, T::timer()) })?;
Ok(())
}
/// Resumes the operation of the previously paused timer
pub fn resume_timer(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_resume(self.speed_mode, T::timer()) })?;
Ok(())
}
fn reset_timer(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_timer_rst(self.speed_mode, T::timer()) })?;
Ok(())
}
fn stop(&mut self) -> Result<(), EspError> {
esp!(unsafe { ledc_stop(self.timer.borrow().speed_mode, C::channel(), IDLE_LEVEL) })?;
esp!(unsafe { ledc_stop(self.speed_mode, C::channel(), IDLE_LEVEL) })?;
Ok(())
}
fn update_duty(&mut self, duty: Duty) -> Result<(), EspError> {
esp!(unsafe {
ledc_set_duty_and_update(
self.timer.borrow().speed_mode,
self.speed_mode,
C::channel(),
duty as u32,
Default::default(),
@ -257,8 +231,15 @@ impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> Channel<C, H,
}
}
impl<'d, C: LedcChannel, T: LedcTimer> Drop for LedcDriver<'d, C, T> {
fn drop(&mut self) {
self.reset_timer().unwrap();
self.stop().unwrap();
}
}
// PwmPin temporarily removed from embedded-hal-1.0.alpha7 in anticipation of e-hal 1.0 release
// impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> embedded_hal::pwm::blocking::PwmPin for Channel<C, H, T, P> {
// impl<'d, C: LedcChannel, T: LedcTimer> embedded_hal::pwm::blocking::PwmPin for LedcDriver<'d, C, T> {
// type Duty = Duty;
// type Error = EspError;
@ -283,9 +264,7 @@ impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> Channel<C, H,
// }
// }
impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> embedded_hal_0_2::PwmPin
for Channel<C, H, T, P>
{
impl<'d, C: LedcChannel, T: LedcTimer> embedded_hal_0_2::PwmPin for LedcDriver<'d, C, T> {
type Duty = Duty;
fn disable(&mut self) {
@ -316,9 +295,9 @@ impl<C: HwChannel, H: HwTimer, T: Borrow<Timer<H>>, P: OutputPin> embedded_hal_0
}
mod chip {
use core::marker::PhantomData;
use esp_idf_sys::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Resolution {
Bits1,
Bits2,
@ -417,33 +396,20 @@ mod chip {
}
/// LED Control peripheral timer
pub trait HwTimer {
pub trait LedcTimer {
fn timer() -> ledc_timer_t;
}
/// LED Control peripheral output channel
pub trait HwChannel {
pub trait LedcChannel {
fn channel() -> ledc_channel_t;
}
macro_rules! impl_timer {
($instance:ident: $timer:expr) => {
pub struct $instance {
_marker: PhantomData<ledc_timer_t>,
}
crate::impl_peripheral!($instance);
impl $instance {
/// # Safety
///
/// It is safe to instantiate this timer exactly one time.
pub unsafe fn new() -> Self {
$instance {
_marker: PhantomData,
}
}
}
impl HwTimer for $instance {
impl LedcTimer for $instance {
fn timer() -> ledc_timer_t {
$timer
}
@ -458,23 +424,9 @@ mod chip {
macro_rules! impl_channel {
($instance:ident: $channel:expr) => {
pub struct $instance {
_marker: PhantomData<ledc_channel_t>,
}
crate::impl_peripheral!($instance);
impl $instance {
/// # Safety
///
/// It is safe to instantiate this output channel exactly one
/// time.
pub unsafe fn new() -> Self {
$instance {
_marker: PhantomData,
}
}
}
impl HwChannel for $instance {
impl LedcChannel for $instance {
fn channel() -> ledc_channel_t {
$channel
}
@ -494,7 +446,7 @@ mod chip {
impl_channel!(CHANNEL7: ledc_channel_t_LEDC_CHANNEL_7);
/// The LED Control device peripheral
pub struct Peripheral {
pub struct LEDC {
pub timer0: TIMER0,
pub timer1: TIMER1,
pub timer2: TIMER2,
@ -511,7 +463,7 @@ mod chip {
pub channel7: CHANNEL7,
}
impl Peripheral {
impl LEDC {
/// Creates a new instance of the LEDC peripheral. Typically one wants
/// to use the instance [`ledc`](crate::peripherals::Peripherals::ledc) from
/// the device peripherals obtained via

View File

@ -39,20 +39,24 @@ pub mod i2c;
pub mod interrupt;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod ledc;
#[cfg(not(feature = "riscv-ulp-hal"))]
#[cfg(all(
any(all(esp32, esp_idf_eth_use_esp32_emac), esp_idf_eth_use_openeth),
not(feature = "riscv-ulp-hal")
))]
pub mod mac;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod modem;
pub mod peripheral;
pub mod peripherals;
pub mod prelude;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod rmt;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod serial;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod spi;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod task;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod uart;
#[cfg(all(any(esp32, esp32s2, esp32s3), not(feature = "riscv-ulp-hal")))]
pub mod ulp;
pub mod units;
@ -124,5 +128,55 @@ macro_rules! embedded_hal_error {
};
}
#[allow(unused_macros)]
macro_rules! into_ref {
($($name:ident),*) => {
$(
let $name = $name.into_ref();
)*
}
}
#[allow(unused_macros)]
macro_rules! impl_peripheral_trait {
($type:ident) => {
unsafe impl Send for $type {}
impl $crate::peripheral::Peripheral for $type {
type P = $type;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
$type { ..*self }
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_peripheral {
($type:ident) => {
pub struct $type(::core::marker::PhantomData<*const ()>);
impl $type {
/// # Safety
///
/// Care should be taken not to instnatiate this peripheralinstance, if it is already instantiated and used elsewhere
#[inline(always)]
pub unsafe fn new() -> Self {
$type(::core::marker::PhantomData)
}
}
$crate::impl_peripheral_trait!($type);
};
}
#[allow(unused_imports)]
pub(crate) use embedded_hal_error;
#[allow(unused_imports)]
pub(crate) use impl_peripheral;
#[allow(unused_imports)]
pub(crate) use impl_peripheral_trait;
#[allow(unused_imports)]
pub(crate) use into_ref;

View File

@ -1,12 +1 @@
pub struct Mac(::core::marker::PhantomData<*const ()>);
impl Mac {
/// # Safety
///
/// Care should be taken not to instnatiate this Mac instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
Mac(::core::marker::PhantomData)
}
}
unsafe impl Send for Mac {}
crate::impl_peripheral!(MAC);

View File

@ -1,18 +1,33 @@
use core::marker::PhantomData;
use crate::peripheral::Peripheral;
#[cfg(not(esp32s2))]
pub use split::*;
pub trait WifiModemCap {}
pub trait WifiModemPeripheral: Peripheral<P = Self> {}
pub trait BluetoothModemCap {}
#[cfg(not(esp32s2))]
pub trait BluetoothModemPeripheral: Peripheral<P = Self> {}
pub struct Modem(::core::marker::PhantomData<*const ()>);
#[cfg(not(esp32s2))]
pub struct Modem(PhantomData<*const ()>, WifiModem, BluetoothModem);
#[cfg(esp32s2)]
pub struct Modem(PhantomData<*const ()>);
impl Modem {
/// # Safety
///
/// Care should be taken not to instnatiate this Mac instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
Modem(::core::marker::PhantomData)
#[cfg(not(esp32s2))]
let this = Modem(PhantomData, WifiModem::new(), BluetoothModem::new());
#[cfg(esp32s2)]
let this = Modem(PhantomData);
this
}
#[cfg(all(not(esp32s2), esp_idf_esp32_wifi_sw_coexist_enable))]
@ -21,29 +36,33 @@ impl Modem {
}
#[cfg(all(not(esp32s2), esp_idf_esp32_wifi_sw_coexist_enable))]
pub fn combine(_wifi_modem: WifiModem, _bt_modem: BluetoothModem) -> Self {
unsafe { Self::new() }
pub fn split_ref(&mut self) -> (&mut WifiModem, &mut BluetoothModem) {
unsafe { (WifiModem(PhantomData), BluetoothModem(PhantomData)) }
}
}
unsafe impl Send for Modem {}
impl WifiModemCap for Modem {}
impl Peripheral for Modem {
type P = Self;
unsafe fn clone_unchecked(&mut self) -> Self::P {
Self::new()
}
}
impl WifiModemPeripheral for Modem {}
#[cfg(not(esp32s2))]
impl BluetoothModemCap for Modem {}
impl BluetoothModemPeripheral for Modem {}
#[cfg(not(esp32s2))]
mod split {
pub struct WifiModem(::core::marker::PhantomData<*const ()>);
crate::impl_peripheral!(WifiModem);
unsafe impl Send for WifiModem {}
impl super::WifiModemPeripheral for WifiModem {}
impl super::WifiModemCap for WifiModem {}
crate::impl_peripheral!(BluetoothModem);
pub struct BluetoothModem(::core::marker::PhantomData<*const ()>);
unsafe impl Send for BluetoothModem {}
impl super::BluetoothModemCap for BluetoothModem {}
impl super::BluetoothModemPeripheral for BluetoothModem {}
}

173
src/peripheral.rs Normal file
View File

@ -0,0 +1,173 @@
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
/// An exclusive reference to a peripheral.
///
/// This is functionally the same as a `&'a mut T`. The reason for having a
/// dedicated struct is memory efficiency:
///
/// Peripheral singletons are typically either zero-sized (for concrete peripehrals
/// like `PA9` or `Spi4`) or very small (for example `AnyPin` which is 1 byte).
/// However `&mut T` is always 4 bytes for 32-bit targets, even if T is zero-sized.
/// PeripheralRef stores a copy of `T` instead, so it's the same size.
///
/// but it is the size of `T` not the size
/// of a pointer. This is useful if T is a zero sized type.
pub struct PeripheralRef<'a, T> {
inner: T,
_lifetime: PhantomData<&'a mut T>,
}
impl<'a, T> PeripheralRef<'a, T> {
#[inline]
pub fn new(inner: T) -> Self {
Self {
inner,
_lifetime: PhantomData,
}
}
/// Unsafely clone (duplicate) a peripheral singleton.
///
/// # Safety
///
/// This returns an owned clone of the peripheral. You must manually ensure
/// only one copy of the peripheral is in use at a time. For example, don't
/// create two SPI drivers on `SPI1`, because they will "fight" each other.
///
/// You should strongly prefer using `reborrow()` instead. It returns a
/// `PeripheralRef` that borrows `self`, which allows the borrow checker
/// to enforce this at compile time.
pub unsafe fn clone_unchecked(&mut self) -> PeripheralRef<'a, T>
where
T: Peripheral<P = T>,
{
PeripheralRef::new(self.inner.clone_unchecked())
}
/// Reborrow into a "child" PeripheralRef.
///
/// `self` will stay borrowed until the child PeripheralRef is dropped.
pub fn reborrow(&mut self) -> PeripheralRef<'_, T>
where
T: Peripheral<P = T>,
{
// safety: we're returning the clone inside a new PeripheralRef that borrows
// self, so user code can't use both at the same time.
PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
}
/// Map the inner peripheral using `Into`.
///
/// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, using an
/// `Into` impl to convert from `T` to `U`.
///
/// For example, this can be useful to degrade GPIO pins: converting from PeripheralRef<'a, PB11>` to `PeripheralRef<'a, AnyPin>`.
#[inline]
pub fn map_into<U>(self) -> PeripheralRef<'a, U>
where
T: Into<U>,
{
PeripheralRef {
inner: self.inner.into(),
_lifetime: PhantomData,
}
}
}
impl<'a, T> Deref for PeripheralRef<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, T> DerefMut for PeripheralRef<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
/// Trait for any type that can be used as a peripheral of type `P`.
///
/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`),
/// or borrowed peripherals (e.g. `&mut TWISPI0`).
///
/// For example, if you have a driver with a constructor like this:
///
/// ```ignore
/// impl<'d, T: Instance> Twim<'d, T> {
/// pub fn new(
/// twim: impl Peripheral<P = T> + 'd,
/// irq: impl Peripheral<P = T::Interrupt> + 'd,
/// sda: impl Peripheral<P = impl GpioPin> + 'd,
/// scl: impl Peripheral<P = impl GpioPin> + 'd,
/// config: Config,
/// ) -> Self { .. }
/// }
/// ```
///
/// You may call it with owned peripherals, which yields an instance that can live forever (`'static`):
///
/// ```ignore
/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
/// ```
///
/// Or you may call it with borrowed peripherals, which yields an instance that can only live for as long
/// as the borrows last:
///
/// ```ignore
/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
/// ```
///
/// # Implementation details, for HAL authors
///
/// When writing a HAL, the intended way to use this trait is to take `impl Peripheral<P = ..>` in
/// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`,
/// and storing that in the driver struct.
///
/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
pub trait Peripheral: Sized {
/// Peripheral singleton type
type P;
/// Unsafely clone (duplicate) a peripheral singleton.
///
/// # Safety
///
/// This returns an owned clone of the peripheral. You must manually ensure
/// only one copy of the peripheral is in use at a time. For example, don't
/// create two SPI drivers on `SPI1`, because they will "fight" each other.
///
/// You should strongly prefer using `into_ref()` instead. It returns a
/// `PeripheralRef`, which allows the borrow checker to enforce this at compile time.
unsafe fn clone_unchecked(&mut self) -> Self::P;
/// Convert a value into a `PeripheralRef`.
///
/// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
/// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
#[inline]
fn into_ref<'a>(mut self) -> PeripheralRef<'a, Self::P>
where
Self: 'a,
{
PeripheralRef::new(unsafe { self.clone_unchecked() })
}
}
impl<'b, T: DerefMut> Peripheral for T
where
T::Target: Peripheral,
{
type P = <T::Target as Peripheral>::P;
#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
self.deref_mut().clone_unchecked()
}
}

View File

@ -6,16 +6,19 @@ use crate::gpio;
use crate::i2c;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::ledc;
#[cfg(all(esp32, not(feature = "riscv-ulp-hal")))]
#[cfg(all(
any(all(esp32, esp_idf_eth_use_esp32_emac), esp_idf_eth_use_openeth),
not(feature = "riscv-ulp-hal")
))]
use crate::mac;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::modem;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::rmt;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::serial;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::spi;
#[cfg(not(feature = "riscv-ulp-hal"))]
use crate::uart;
#[cfg(all(
any(esp32, esp32s2, esp32s3),
not(feature = "riscv-ulp-hal"),
@ -26,11 +29,11 @@ use crate::ulp;
pub struct Peripherals {
pub pins: gpio::Pins,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub uart0: serial::UART0,
pub uart0: uart::UART0,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub uart1: serial::UART1,
pub uart1: uart::UART1,
#[cfg(all(esp32, not(feature = "riscv-ulp-hal")))]
pub uart2: serial::UART2,
pub uart2: uart::UART2,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub i2c0: i2c::I2C0,
#[cfg(all(not(esp32c3), not(feature = "riscv-ulp-hal")))]
@ -48,17 +51,20 @@ pub struct Peripherals {
#[cfg(not(feature = "riscv-ulp-hal"))]
pub can: can::CAN,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub ledc: ledc::Peripheral,
pub ledc: ledc::LEDC,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub rmt: rmt::Peripheral,
pub rmt: rmt::RMT,
#[cfg(all(
any(esp32, esp32s2, esp32s3),
not(feature = "riscv-ulp-hal"),
esp_idf_comp_ulp_enabled
))]
pub ulp: ulp::ULP,
#[cfg(all(esp32, not(feature = "riscv-ulp-hal")))]
pub mac: mac::Mac,
#[cfg(all(
any(all(esp32, esp_idf_eth_use_esp32_emac), esp_idf_eth_use_openeth),
not(feature = "riscv-ulp-hal")
))]
pub mac: mac::MAC,
#[cfg(not(feature = "riscv-ulp-hal"))]
pub modem: modem::Modem,
}
@ -109,11 +115,11 @@ impl Peripherals {
Self {
pins: gpio::Pins::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
uart0: serial::UART0::new(),
uart0: uart::UART0::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
uart1: serial::UART1::new(),
uart1: uart::UART1::new(),
#[cfg(all(esp32, not(feature = "riscv-ulp-hal")))]
uart2: serial::UART2::new(),
uart2: uart::UART2::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
i2c0: i2c::I2C0::new(),
#[cfg(all(not(esp32c3), not(feature = "riscv-ulp-hal")))]
@ -131,17 +137,20 @@ impl Peripherals {
#[cfg(not(feature = "riscv-ulp-hal"))]
can: can::CAN::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
ledc: ledc::Peripheral::new(),
ledc: ledc::LEDC::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
rmt: rmt::Peripheral::new(),
rmt: rmt::RMT::new(),
#[cfg(all(
any(esp32, esp32s2, esp32s3),
not(feature = "riscv-ulp-hal"),
esp_idf_comp_ulp_enabled
))]
ulp: ulp::ULP::new(),
#[cfg(all(esp32, not(feature = "riscv-ulp-hal")))]
mac: mac::Mac::new(),
#[cfg(all(
any(all(esp32, esp_idf_eth_use_esp32_emac), esp_idf_eth_use_openeth),
not(feature = "riscv-ulp-hal")
))]
mac: mac::MAC::new(),
#[cfg(not(feature = "riscv-ulp-hal"))]
modem: modem::Modem::new(),
}

View File

@ -26,7 +26,7 @@
//! let channel = peripherals.rmt.channel0;
//!
//! // Create an RMT transmitter.
//! let tx = Transmit::new(pin, channel, &config)?;
//! let tx = RmtDriver::new(pin, channel, &config)?;
//!
//! // Prepare signal pulse signal to be sent.
//! let low = Pulse::new(PinState::Low, PulseTicks::new(10)?);
@ -51,21 +51,26 @@
//! [VariableLengthSignal] allows you to use the heap and incrementally add pulse items without knowing the size
//! ahead of time.
use core::convert::TryFrom;
use core::time::Duration;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::cell::UnsafeCell;
use core::convert::TryFrom;
use core::time::Duration;
pub use chip::*;
use config::TransmitConfig;
use esp_idf_sys::*;
use crate::gpio::OutputPin;
use crate::peripheral::{Peripheral, PeripheralRef};
use crate::units::Hertz;
use config::Config;
pub use chip::*;
/// A `Low` (0) or `High` (1) state for a pin.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PinState {
@ -217,21 +222,14 @@ pub mod config {
pub duty_percent: DutyPercent,
}
impl Default for CarrierConfig {
/// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
fn default() -> Self {
impl CarrierConfig {
pub fn new() -> Self {
Self {
frequency: 38.kHz().into(),
carrier_level: PinState::High,
duty_percent: DutyPercent(33),
}
}
}
impl CarrierConfig {
pub fn new() -> Self {
Default::default()
}
pub fn frequency(mut self, hz: Hertz) -> Self {
self.frequency = hz;
@ -249,6 +247,13 @@ pub mod config {
}
}
impl Default for CarrierConfig {
/// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
fn default() -> Self {
Self::new()
}
}
/// Configuration setting for looping a signal.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Loop {
@ -259,7 +264,7 @@ pub mod config {
}
/// Used when creating a [`Transmit`][crate::rmt::Transmit] instance.
pub struct TransmitConfig {
pub struct Config {
pub clock_divider: u8,
pub mem_block_num: u8,
pub carrier: Option<CarrierConfig>,
@ -276,9 +281,8 @@ pub mod config {
pub aware_dfs: bool,
}
impl Default for TransmitConfig {
/// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
fn default() -> Self {
impl Config {
pub fn new() -> Self {
Self {
aware_dfs: false,
mem_block_num: 1,
@ -288,12 +292,6 @@ pub mod config {
idle: Some(PinState::Low),
}
}
}
impl TransmitConfig {
pub fn new() -> Self {
Self::default()
}
pub fn aware_dfs(mut self, enable: bool) -> Self {
self.aware_dfs = enable;
@ -325,26 +323,37 @@ pub mod config {
self
}
}
impl Default for Config {
/// Defaults from `<https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/rmt.h#L101>`
fn default() -> Self {
Self::new()
}
}
}
/// The RMT transmitter.
/// The RMT transmitter driver.
///
/// Use [`Transmit::start()`] or [`Transmit::start_blocking()`] to transmit pulses.
/// Use [`RmtDriver::start()`] or [`RmtDriver::start_blocking()`] to transmit pulses.
///
/// See the [rmt module][crate::rmt] for more information.
pub struct Transmit<P: OutputPin, C: HwChannel> {
pin: P,
channel: C,
pub struct RmtDriver<'d, C: RmtChannel> {
_channel: PeripheralRef<'d, C>,
}
impl<P: OutputPin, C: HwChannel> Transmit<P, C> {
impl<'d, C: RmtChannel> RmtDriver<'d, C> {
/// Initialise the rmt module with the specified pin, channel and configuration.
///
/// To uninstall the driver and return ownership of the `channel` and `pin` use
/// [`Transmit::release()`].
/// To uninstall the driver just drop it.
///
/// Internally this calls `rmt_config()` and `rmt_driver_install()`.
pub fn new(pin: P, channel: C, config: &TransmitConfig) -> Result<Self, EspError> {
pub fn new(
channel: impl Peripheral<P = C> + 'd,
pin: impl Peripheral<P = impl OutputPin> + 'd,
config: &Config,
) -> Result<Self, EspError> {
crate::into_ref!(channel, pin);
let mut flags = 0;
if config.aware_dfs {
flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
@ -383,7 +392,7 @@ impl<P: OutputPin, C: HwChannel> Transmit<P, C> {
esp!(rmt_driver_install(C::channel(), 0, 0))?;
}
Ok(Self { pin, channel })
Ok(Self { _channel: channel })
}
/// Get speed of the channels internal counter clock.
@ -553,15 +562,6 @@ impl<P: OutputPin, C: HwChannel> Transmit<P, C> {
esp!(unsafe { rmt_tx_stop(C::channel()) })
}
/// Stop transmitting and release the driver.
///
/// This will return the pin and channel.
pub fn release(mut self) -> Result<(P, C), EspError> {
self.stop()?;
esp!(unsafe { rmt_driver_uninstall(C::channel()) })?;
Ok((self.pin, self.channel))
}
pub fn set_looping(&mut self, looping: config::Loop) -> Result<(), EspError> {
esp!(unsafe { rmt_set_tx_loop_mode(C::channel(), looping != config::Loop::None) })?;
@ -580,6 +580,14 @@ impl<P: OutputPin, C: HwChannel> Transmit<P, C> {
}
}
impl<'d, C: RmtChannel> Drop for RmtDriver<'d, C> {
/// Stop transmitting and release the driver.
fn drop(&mut self) {
self.stop().unwrap();
esp!(unsafe { rmt_driver_uninstall(C::channel()) }).unwrap();
}
}
/// Signal storage for [`Transmit`] in a format ready for the RMT driver.
pub trait Signal {
fn as_slice(&self) -> &[rmt_item32_t];
@ -756,33 +764,18 @@ impl Signal for VariableLengthSignal {
}
mod chip {
use core::marker::PhantomData;
use esp_idf_sys::*;
/// RMT peripheral channel.
pub trait HwChannel {
pub trait RmtChannel {
fn channel() -> rmt_channel_t;
}
macro_rules! impl_channel {
($instance:ident: $channel:expr) => {
pub struct $instance {
_marker: PhantomData<rmt_channel_t>,
}
crate::impl_peripheral!($instance);
impl $instance {
/// # Safety
///
/// It is safe to instantiate this channel exactly one time.
pub unsafe fn new() -> Self {
$instance {
_marker: PhantomData,
}
}
}
impl HwChannel for $instance {
impl RmtChannel for $instance {
fn channel() -> rmt_channel_t {
$channel
}
@ -805,7 +798,7 @@ mod chip {
#[cfg(any(esp32, esp32s3))]
impl_channel!(CHANNEL7: rmt_channel_t_RMT_CHANNEL_7);
pub struct Peripheral {
pub struct RMT {
pub channel0: CHANNEL0,
pub channel1: CHANNEL1,
pub channel2: CHANNEL2,
@ -820,7 +813,7 @@ mod chip {
pub channel7: CHANNEL7,
}
impl Peripheral {
impl RMT {
/// Creates a new instance of the RMT peripheral. Typically one wants
/// to use the instance [`rmt`](crate::peripherals::Peripherals::rmt) from
/// the device peripherals obtained via

View File

@ -21,13 +21,16 @@
//! - Slave
use core::cmp::{max, min, Ordering};
use core::marker::PhantomData;
use core::ptr;
use embedded_hal::spi::blocking::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite, SpiDevice};
use esp_idf_sys::*;
use crate::delay::portMAX_DELAY;
use crate::gpio::{self, InputPin, OutputPin};
use esp_idf_sys::*;
use crate::peripheral::{Peripheral, PeripheralRef};
crate::embedded_hal_error!(
SpiError,
@ -39,15 +42,7 @@ pub trait Spi: Send {
fn device() -> spi_host_device_t;
}
// Limit to 64, as we sometimes allocate a buffer of size TRANS_LEN on the stack, so we have to keep it small
// SOC_SPI_MAXIMUM_BUFFER_SIZE equals 64 or 72 (esp32s2) anyway
const TRANS_LEN: usize = if SOC_SPI_MAXIMUM_BUFFER_SIZE < 64_u32 {
SOC_SPI_MAXIMUM_BUFFER_SIZE as _
} else {
64_usize
};
#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Dma {
Disabled,
Channel1(usize),
@ -82,20 +77,6 @@ impl Dma {
}
}
/// Pins used by the SPI interface
pub struct Pins<
SCLK: OutputPin,
SDO: OutputPin,
// default pins to allow type inference
SDI: InputPin + OutputPin = crate::gpio::Gpio1<crate::gpio::Input>,
CS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
pub sclk: SCLK,
pub sdo: SDO,
pub sdi: Option<SDI>,
pub cs: Option<CS>,
}
/// SPI configuration
pub mod config {
use crate::spi::Dma;
@ -187,73 +168,397 @@ pub mod config {
}
}
pub struct SpiBusMasterDriver<'d> {
handle: spi_device_handle_t,
trans_len: usize,
_p: PhantomData<&'d ()>,
}
impl<'d> SpiBusMasterDriver<'d> {
fn polling_transmit(
&mut self,
read: *mut u8,
write: *const u8,
transaction_length: usize,
rx_length: usize,
) -> Result<(), SpiError> {
polling_transmit(
self.handle,
read,
write,
transaction_length,
rx_length,
true,
)
}
/// Empty transaction to de-assert CS.
fn finish(&mut self) -> Result<(), SpiError> {
polling_transmit(self.handle, ptr::null_mut(), ptr::null(), 0, 0, false)
}
}
impl<'d> embedded_hal::spi::ErrorType for SpiBusMasterDriver<'d> {
type Error = SpiError;
}
impl<'d> SpiBusFlush for SpiBusMasterDriver<'d> {
fn flush(&mut self) -> Result<(), Self::Error> {
// Since we use polling transactions, flushing isn't required.
// In future, when DMA is available spi_device_get_trans_result
// will be called here.
Ok(())
}
}
impl<'d> SpiBusRead for SpiBusMasterDriver<'d> {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
for chunk in words.chunks_mut(self.trans_len) {
self.polling_transmit(chunk.as_mut_ptr(), ptr::null(), chunk.len(), chunk.len())?;
}
Ok(())
}
}
impl<'d> SpiBusWrite for SpiBusMasterDriver<'d> {
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
for chunk in words.chunks(self.trans_len) {
self.polling_transmit(ptr::null_mut(), chunk.as_ptr(), chunk.len(), 0)?;
}
Ok(())
}
}
impl<'d> SpiBus for SpiBusMasterDriver<'d> {
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
let common_length = min(read.len(), write.len());
let common_read = read[0..common_length].chunks_mut(self.trans_len);
let common_write = write[0..common_length].chunks(self.trans_len);
for (read_chunk, write_chunk) in common_read.zip(common_write) {
self.polling_transmit(
read_chunk.as_mut_ptr(),
write_chunk.as_ptr(),
max(read_chunk.len(), write_chunk.len()),
read_chunk.len(),
)?;
}
match read.len().cmp(&write.len()) {
Ordering::Equal => { /* Nothing left to do */ }
Ordering::Greater => {
// Read remainder
self.read(&mut read[write.len()..])?;
}
Ordering::Less => {
// Write remainder
self.write(&write[read.len()..])?;
}
}
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
for chunk in words.chunks_mut(self.trans_len) {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
self.polling_transmit(ptr, ptr, len, len)?;
}
Ok(())
}
}
/// Master SPI abstraction
pub struct Master<
SPI: Spi,
SCLK: OutputPin,
SDO: OutputPin,
// default pins to allow type inference
SDI: InputPin + OutputPin = crate::gpio::Gpio1<crate::gpio::Input>,
CS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
spi: SPI,
pins: Pins<SCLK, SDO, SDI, CS>,
pub struct SpiMasterDriver<'d, SPI: Spi> {
_spi: PeripheralRef<'d, SPI>,
device: spi_device_handle_t,
max_transfer_size: usize,
}
unsafe impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
Send for Master<SPI, SCLK, SDO, SDI, CS>
{
}
impl<CS: OutputPin>
Master<SPI1, gpio::Gpio6<gpio::Output>, gpio::Gpio7<gpio::Output>, gpio::Gpio8<gpio::Input>, CS>
{
impl<'d> SpiMasterDriver<'d, SPI1> {
/// Create new instance of SPI controller for SPI1
///
/// SPI1 can only use fixed pin for SCLK, SDO and SDI as they are shared with SPI0.
pub fn new(
spi: SPI1,
pins: Pins<
gpio::Gpio6<gpio::Output>,
gpio::Gpio7<gpio::Output>,
gpio::Gpio8<gpio::Input>,
CS,
>,
spi: impl Peripheral<P = SPI1> + 'd,
sclk: impl Peripheral<P = gpio::Gpio6> + 'd,
sdo: impl Peripheral<P = gpio::Gpio7> + 'd,
sdi: Option<impl Peripheral<P = gpio::Gpio8> + 'd>,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: config::Config,
) -> Result<Self, EspError> {
Master::new_internal(spi, pins, config)
SpiMasterDriver::new_internal(spi, sclk, sdo, sdi, cs, config)
}
}
impl<SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
Master<SPI2, SCLK, SDO, SDI, CS>
{
impl<'d> SpiMasterDriver<'d, SPI2> {
/// Create new instance of SPI controller for SPI2
pub fn new(
spi: SPI2,
pins: Pins<SCLK, SDO, SDI, CS>,
spi: impl Peripheral<P = SPI2> + 'd,
sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: config::Config,
) -> Result<Self, EspError> {
Master::new_internal(spi, pins, config)
SpiMasterDriver::new_internal(spi, sclk, sdo, sdi, cs, config)
}
}
#[cfg(not(esp32c3))]
impl<SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
Master<SPI3, SCLK, SDO, SDI, CS>
{
impl<'d> SpiMasterDriver<'d, SPI3> {
/// Create new instance of SPI controller for SPI3
pub fn new(
spi: SPI3,
pins: Pins<SCLK, SDO, SDI, CS>,
spi: impl Peripheral<P = SPI3> + 'd,
sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: config::Config,
) -> Result<Self, EspError> {
Master::new_internal(spi, pins, config)
SpiMasterDriver::new_internal(spi, sclk, sdo, sdi, cs, config)
}
}
impl<'d, SPI: Spi> SpiMasterDriver<'d, SPI> {
/// Internal implementation of new shared by all SPI controllers
fn new_internal(
spi: impl Peripheral<P = SPI> + 'd,
sclk: impl Peripheral<P = impl OutputPin> + 'd,
sdo: impl Peripheral<P = impl OutputPin> + 'd,
sdi: Option<impl Peripheral<P = impl InputPin + OutputPin> + 'd>,
cs: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: config::Config,
) -> Result<Self, EspError> {
crate::into_ref!(spi, sclk, sdo);
let sdi = sdi.map(|sdi| sdi.into_ref());
let cs = cs.map(|cs| cs.into_ref());
#[cfg(any(esp_idf_version = "4.4", esp_idf_version_major = "5"))]
let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER,
sclk_io_num: sclk.pin(),
data4_io_num: -1,
data5_io_num: -1,
data6_io_num: -1,
data7_io_num: -1,
__bindgen_anon_1: spi_bus_config_t__bindgen_ty_1 {
mosi_io_num: sdo.pin(),
//data0_io_num: -1,
},
__bindgen_anon_2: spi_bus_config_t__bindgen_ty_2 {
miso_io_num: sdi.as_ref().map_or(-1, |p| p.pin()),
//data1_io_num: -1,
},
__bindgen_anon_3: spi_bus_config_t__bindgen_ty_3 {
quadwp_io_num: -1,
//data2_io_num: -1,
},
__bindgen_anon_4: spi_bus_config_t__bindgen_ty_4 {
quadhd_io_num: -1,
//data3_io_num: -1,
},
max_transfer_sz: config.dma.max_transfer_size() as i32,
..Default::default()
};
#[cfg(not(any(esp_idf_version = "4.4", esp_idf_version_major = "5")))]
let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER,
sclk_io_num: sclk.pin(),
mosi_io_num: sdo.pin(),
miso_io_num: sdi.as_ref().map_or(-1, |p| p.pin()),
quadwp_io_num: -1,
quadhd_io_num: -1,
max_transfer_sz: config.dma.max_transfer_size() as i32,
..Default::default()
};
esp!(unsafe { spi_bus_initialize(SPI::device(), &bus_config, config.dma.into()) })?;
let device_config = spi_device_interface_config_t {
spics_io_num: cs.as_ref().map_or(-1, |p| p.pin()),
clock_speed_hz: config.baudrate.0 as i32,
mode: (((config.data_mode.polarity == embedded_hal::spi::Polarity::IdleHigh) as u8)
<< 1)
| ((config.data_mode.phase == embedded_hal::spi::Phase::CaptureOnSecondTransition)
as u8),
queue_size: 64,
flags: if config.write_only {
SPI_DEVICE_NO_DUMMY
} else {
0_u32
},
..Default::default()
};
let mut device_handle: spi_device_handle_t = ptr::null_mut();
esp!(unsafe {
spi_bus_add_device(SPI::device(), &device_config, &mut device_handle as *mut _)
})?;
Ok(Self {
_spi: spi,
device: device_handle,
max_transfer_size: config.dma.max_transfer_size(),
})
}
fn lock_bus(&mut self) -> Result<Lock, SpiError> {
Lock::new(self.device).map_err(SpiError::other)
}
}
impl<'d, SPI: Spi> Drop for SpiMasterDriver<'d, SPI> {
fn drop(&mut self) {
esp!(unsafe { spi_bus_remove_device(self.device) }).unwrap();
esp!(unsafe { spi_bus_free(SPI::device()) }).unwrap();
}
}
unsafe impl<'d, SPI: Spi> Send for SpiMasterDriver<'d, SPI> {}
impl<'d, SPI: Spi> embedded_hal::spi::ErrorType for SpiMasterDriver<'d, SPI> {
type Error = SpiError;
}
impl<'d, SPI: Spi> SpiDevice for SpiMasterDriver<'d, SPI> {
type Bus = SpiBusMasterDriver<'d>;
fn transaction<R>(
&mut self,
f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as embedded_hal::spi::ErrorType>::Error>,
) -> Result<R, Self::Error> {
let mut bus = SpiBusMasterDriver {
handle: self.device,
trans_len: self.max_transfer_size,
_p: PhantomData,
};
let lock = self.lock_bus()?;
let trans_result = f(&mut bus);
let finish_result = bus.finish();
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
let flush_result = bus.flush();
core::mem::drop(lock);
let result = trans_result?;
finish_result?;
flush_result?;
Ok(result)
}
}
impl<'d, SPI: Spi> embedded_hal_0_2::blocking::spi::Transfer<u8> for SpiMasterDriver<'d, SPI> {
type Error = SpiError;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
let _lock = self.lock_bus();
let mut chunks = words.chunks_mut(self.max_transfer_size).peekable();
while let Some(chunk) = chunks.next() {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
polling_transmit(self.device, ptr, ptr, len, len, chunks.peek().is_some())?;
}
Ok(words)
}
}
impl<'d, SPI: Spi> embedded_hal_0_2::blocking::spi::Write<u8> for SpiMasterDriver<'d, SPI> {
type Error = SpiError;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let _lock = self.lock_bus();
let mut chunks = words.chunks(self.max_transfer_size).peekable();
while let Some(chunk) = chunks.next() {
polling_transmit(
self.device,
ptr::null_mut(),
chunk.as_ptr(),
chunk.len(),
0,
chunks.peek().is_some(),
)?;
}
Ok(())
}
}
impl<'d, SPI: Spi> embedded_hal_0_2::blocking::spi::WriteIter<u8> for SpiMasterDriver<'d, SPI> {
type Error = SpiError;
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
where
WI: IntoIterator<Item = u8>,
{
let mut words = words.into_iter();
let mut buf = [0_u8; TRANS_LEN];
self.transaction(|bus| {
loop {
let mut offset = 0_usize;
while offset < buf.len() {
if let Some(word) = words.next() {
buf[offset] = word;
offset += 1;
} else {
break;
}
}
if offset == 0 {
break;
}
bus.write(&buf[..offset])?;
}
Ok(())
})
}
}
impl<'d, SPI: Spi> embedded_hal_0_2::blocking::spi::Transactional<u8> for SpiMasterDriver<'d, SPI> {
type Error = SpiError;
fn exec<'a>(
&mut self,
operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'a, u8>],
) -> Result<(), Self::Error> {
self.transaction(|bus| {
for operation in operations {
match operation {
embedded_hal_0_2::blocking::spi::Operation::Write(write) => bus.write(write),
embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
bus.transfer_in_place(words)
}
}?;
}
Ok(())
})
}
}
// Limit to 64, as we sometimes allocate a buffer of size TRANS_LEN on the stack, so we have to keep it small
// SOC_SPI_MAXIMUM_BUFFER_SIZE equals 64 or 72 (esp32s2) anyway
const TRANS_LEN: usize = if SOC_SPI_MAXIMUM_BUFFER_SIZE < 64_u32 {
SOC_SPI_MAXIMUM_BUFFER_SIZE as _
} else {
64_usize
};
struct Lock(spi_device_handle_t);
impl Lock {
@ -272,11 +577,6 @@ impl Drop for Lock {
}
}
pub struct MasterBus {
handle: spi_device_handle_t,
trans_len: usize,
}
// These parameters assume full duplex.
fn polling_transmit(
handle: spi_device_handle_t,
@ -315,351 +615,9 @@ fn polling_transmit(
.map_err(SpiError::other)
}
impl MasterBus {
fn polling_transmit(
&mut self,
read: *mut u8,
write: *const u8,
transaction_length: usize,
rx_length: usize,
) -> Result<(), SpiError> {
polling_transmit(
self.handle,
read,
write,
transaction_length,
rx_length,
true,
)
}
/// Empty transaction to de-assert CS.
fn finish(&mut self) -> Result<(), SpiError> {
polling_transmit(self.handle, ptr::null_mut(), ptr::null(), 0, 0, false)
}
}
impl embedded_hal::spi::ErrorType for MasterBus {
type Error = SpiError;
}
impl SpiBusFlush for MasterBus {
fn flush(&mut self) -> Result<(), Self::Error> {
// Since we use polling transactions, flushing isn't required.
// In future, when DMA is available spi_device_get_trans_result
// will be called here.
Ok(())
}
}
impl SpiBusRead for MasterBus {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
for chunk in words.chunks_mut(self.trans_len) {
self.polling_transmit(chunk.as_mut_ptr(), ptr::null(), chunk.len(), chunk.len())?;
}
Ok(())
}
}
impl SpiBusWrite for MasterBus {
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
for chunk in words.chunks(self.trans_len) {
self.polling_transmit(ptr::null_mut(), chunk.as_ptr(), chunk.len(), 0)?;
}
Ok(())
}
}
impl SpiBus for MasterBus {
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
let common_length = min(read.len(), write.len());
let common_read = read[0..common_length].chunks_mut(self.trans_len);
let common_write = write[0..common_length].chunks(self.trans_len);
for (read_chunk, write_chunk) in common_read.zip(common_write) {
self.polling_transmit(
read_chunk.as_mut_ptr(),
write_chunk.as_ptr(),
max(read_chunk.len(), write_chunk.len()),
read_chunk.len(),
)?;
}
match read.len().cmp(&write.len()) {
Ordering::Equal => { /* Nothing left to do */ }
Ordering::Greater => {
// Read remainder
self.read(&mut read[write.len()..])?;
}
Ordering::Less => {
// Write remainder
self.write(&write[read.len()..])?;
}
}
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
for chunk in words.chunks_mut(self.trans_len) {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
self.polling_transmit(ptr, ptr, len, len)?;
}
Ok(())
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
Master<SPI, SCLK, SDO, SDI, CS>
{
/// Internal implementation of new shared by all SPI controllers
fn new_internal(
spi: SPI,
pins: Pins<SCLK, SDO, SDI, CS>,
config: config::Config,
) -> Result<Self, EspError> {
#[cfg(any(esp_idf_version = "4.4", esp_idf_version_major = "5"))]
let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER,
sclk_io_num: pins.sclk.pin(),
data4_io_num: -1,
data5_io_num: -1,
data6_io_num: -1,
data7_io_num: -1,
__bindgen_anon_1: spi_bus_config_t__bindgen_ty_1 {
mosi_io_num: pins.sdo.pin(),
//data0_io_num: -1,
},
__bindgen_anon_2: spi_bus_config_t__bindgen_ty_2 {
miso_io_num: pins.sdi.as_ref().map_or(-1, |p| p.pin()),
//data1_io_num: -1,
},
__bindgen_anon_3: spi_bus_config_t__bindgen_ty_3 {
quadwp_io_num: -1,
//data2_io_num: -1,
},
__bindgen_anon_4: spi_bus_config_t__bindgen_ty_4 {
quadhd_io_num: -1,
//data3_io_num: -1,
},
max_transfer_sz: config.dma.max_transfer_size() as i32,
..Default::default()
};
#[cfg(not(any(esp_idf_version = "4.4", esp_idf_version_major = "5")))]
let bus_config = spi_bus_config_t {
flags: SPICOMMON_BUSFLAG_MASTER,
sclk_io_num: pins.sclk.pin(),
mosi_io_num: pins.sdo.pin(),
miso_io_num: pins.sdi.as_ref().map_or(-1, |p| p.pin()),
quadwp_io_num: -1,
quadhd_io_num: -1,
max_transfer_sz: config.dma.max_transfer_size() as i32,
..Default::default()
};
esp!(unsafe { spi_bus_initialize(SPI::device(), &bus_config, config.dma.into()) })?;
let device_config = spi_device_interface_config_t {
spics_io_num: pins.cs.as_ref().map_or(-1, |p| p.pin()),
clock_speed_hz: config.baudrate.0 as i32,
mode: (((config.data_mode.polarity == embedded_hal::spi::Polarity::IdleHigh) as u8)
<< 1)
| ((config.data_mode.phase == embedded_hal::spi::Phase::CaptureOnSecondTransition)
as u8),
queue_size: 64,
flags: if config.write_only {
SPI_DEVICE_NO_DUMMY
} else {
0_u32
},
..Default::default()
};
let mut device_handle: spi_device_handle_t = ptr::null_mut();
esp!(unsafe {
spi_bus_add_device(SPI::device(), &device_config, &mut device_handle as *mut _)
})?;
Ok(Self {
spi,
pins,
device: device_handle,
max_transfer_size: config.dma.max_transfer_size(),
})
}
/// Release and return the raw interface to the underlying SPI peripheral
#[allow(clippy::type_complexity)]
pub fn release(self) -> Result<(SPI, Pins<SCLK, SDO, SDI, CS>), EspError> {
esp!(unsafe { spi_bus_remove_device(self.device) })?;
esp!(unsafe { spi_bus_free(SPI::device()) })?;
Ok((self.spi, self.pins))
}
fn lock_bus(&mut self) -> Result<Lock, SpiError> {
Lock::new(self.device).map_err(SpiError::other)
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
embedded_hal::spi::ErrorType for Master<SPI, SCLK, SDO, SDI, CS>
{
type Error = SpiError;
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin> SpiDevice
for Master<SPI, SCLK, SDO, SDI, CS>
{
type Bus = MasterBus;
fn transaction<R>(
&mut self,
f: impl FnOnce(&mut Self::Bus) -> Result<R, <Self::Bus as embedded_hal::spi::ErrorType>::Error>,
) -> Result<R, Self::Error> {
let mut bus = MasterBus {
handle: self.device,
trans_len: self.max_transfer_size,
};
let lock = self.lock_bus()?;
let trans_result = f(&mut bus);
let finish_result = bus.finish();
// Flush whatever is pending.
// Note that this is done even when an error is returned from the transaction.
let flush_result = bus.flush();
core::mem::drop(lock);
let result = trans_result?;
finish_result?;
flush_result?;
Ok(result)
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
embedded_hal_0_2::blocking::spi::Transfer<u8> for Master<SPI, SCLK, SDO, SDI, CS>
{
type Error = SpiError;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
let _lock = self.lock_bus();
let mut chunks = words.chunks_mut(self.max_transfer_size).peekable();
while let Some(chunk) = chunks.next() {
let ptr = chunk.as_mut_ptr();
let len = chunk.len();
polling_transmit(self.device, ptr, ptr, len, len, chunks.peek().is_some())?;
}
Ok(words)
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
embedded_hal_0_2::blocking::spi::Write<u8> for Master<SPI, SCLK, SDO, SDI, CS>
{
type Error = SpiError;
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let _lock = self.lock_bus();
let mut chunks = words.chunks(self.max_transfer_size).peekable();
while let Some(chunk) = chunks.next() {
polling_transmit(
self.device,
ptr::null_mut(),
chunk.as_ptr(),
chunk.len(),
0,
chunks.peek().is_some(),
)?;
}
Ok(())
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
embedded_hal_0_2::blocking::spi::WriteIter<u8> for Master<SPI, SCLK, SDO, SDI, CS>
{
type Error = SpiError;
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
where
WI: IntoIterator<Item = u8>,
{
let mut words = words.into_iter();
let mut buf = [0_u8; TRANS_LEN];
self.transaction(|bus| {
loop {
let mut offset = 0_usize;
while offset < buf.len() {
if let Some(word) = words.next() {
buf[offset] = word;
offset += 1;
} else {
break;
}
}
if offset == 0 {
break;
}
bus.write(&buf[..offset])?;
}
Ok(())
})
}
}
impl<SPI: Spi, SCLK: OutputPin, SDO: OutputPin, SDI: InputPin + OutputPin, CS: OutputPin>
embedded_hal_0_2::blocking::spi::Transactional<u8> for Master<SPI, SCLK, SDO, SDI, CS>
{
type Error = SpiError;
fn exec<'a>(
&mut self,
operations: &mut [embedded_hal_0_2::blocking::spi::Operation<'a, u8>],
) -> Result<(), Self::Error> {
self.transaction(|bus| {
for operation in operations {
match operation {
embedded_hal_0_2::blocking::spi::Operation::Write(write) => bus.write(write),
embedded_hal_0_2::blocking::spi::Operation::Transfer(words) => {
bus.transfer_in_place(words)
}
}?;
}
Ok(())
})
}
}
macro_rules! impl_spi {
($spi:ident: $device:expr) => {
pub struct $spi(::core::marker::PhantomData<*const ()>);
impl $spi {
/// # Safety
///
/// Care should be taken not to instantiate this SPI instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
$spi(::core::marker::PhantomData)
}
}
unsafe impl Send for $spi {}
crate::impl_peripheral!($spi);
impl Spi for $spi {
#[inline(always)]
@ -672,6 +630,5 @@ macro_rules! impl_spi {
impl_spi!(SPI1: spi_host_device_t_SPI1_HOST);
impl_spi!(SPI2: spi_host_device_t_SPI2_HOST);
#[cfg(not(esp32c3))]
impl_spi!(SPI3: spi_host_device_t_SPI3_HOST);

View File

@ -16,21 +16,19 @@
//! let peripherals = Peripherals::take().unwrap();
//! let pins = peripherals.pins;
//!
//! let config = serial::config::Config::default().baudrate(Hertz(115_200));
//! let config = uart::config::Config::default().baudrate(Hertz(115_200));
//!
//! let mut serial: serial::Serial<serial::UART1, _, _> = serial::Serial::new(
//! let mut uart: uart::UartDriver = uart::UartDriver::new(
//! peripherals.uart1,
//! serial::Pins {
//! tx: pins.gpio1,
//! rx: pins.gpio3,
//! cts: None,
//! rts: None,
//! },
//! config
//! pins.gpio1,
//! pins.gpio3,
//! None,
//! None,
//! &config
//! ).unwrap();
//!
//! for i in 0..10 {
//! writeln!(serial, "{:}", format!("count {:}", i)).unwrap();
//! writeln!(uart, "{:}", format!("count {:}", i)).unwrap();
//! }
//! ```
//!
@ -49,17 +47,9 @@ use crate::units::*;
use esp_idf_sys::*;
const UART_FIFO_SIZE: i32 = 128;
use crate::peripheral::{Peripheral, PeripheralRef};
// /// Interrupt event
// pub enum Event {
// /// New data has been received
// Rxne,
// /// New data can be sent
// Txe,
// /// Idle line state detected
// Idle,
// }
const UART_FIFO_SIZE: i32 = 128;
/// UART configuration
pub mod config {
@ -67,7 +57,7 @@ pub mod config {
use esp_idf_sys::*;
/// Number of data bits
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum DataBits {
DataBits5,
DataBits6,
@ -100,7 +90,7 @@ pub mod config {
}
/// Number of data bits
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum FlowControl {
None,
RTS,
@ -136,7 +126,7 @@ pub mod config {
}
/// Parity check
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Parity {
ParityNone,
ParityEven,
@ -280,22 +270,6 @@ pub mod config {
}
}
/// Pins used by the UART interface
///
/// Note that any two pins may be used
pub struct Pins<
TX: OutputPin,
RX: InputPin,
// default pins to allow type inference
CTS: InputPin = crate::gpio::Gpio1<crate::gpio::Input>,
RTS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
pub tx: TX,
pub rx: RX,
pub cts: Option<CTS>,
pub rts: Option<RTS>,
}
pub trait Uart {
fn port() -> uart_port_t;
}
@ -308,39 +282,37 @@ crate::embedded_hal_error!(
/// Serial abstraction
///
pub struct Serial<
UART: Uart,
TX: OutputPin,
RX: InputPin,
// default pins to allow type inference
CTS: InputPin = crate::gpio::Gpio1<crate::gpio::Input>,
RTS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
uart: UART,
pins: Pins<TX, RX, CTS, RTS>,
rx: Rx<UART>,
tx: Tx<UART>,
pub struct UartDriver<'d, UART: Uart> {
_uart: PeripheralRef<'d, UART>,
rx: UartRxDriver<'d, UART>,
tx: UartTxDriver<'d, UART>,
}
/// Serial receiver
pub struct Rx<UART: Uart> {
_uart: PhantomData<UART>,
pub struct UartRxDriver<'d, UART: Uart> {
_uart: PhantomData<&'d UART>,
}
/// Serial transmitter
pub struct Tx<UART: Uart> {
_uart: PhantomData<UART>,
pub struct UartTxDriver<'d, UART: Uart> {
_uart: PhantomData<&'d UART>,
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> UartDriver<'d, UART> {
/// Create a new serial driver
pub fn new(
uart: UART,
pins: Pins<TX, RX, CTS, RTS>,
config: config::Config,
uart: impl Peripheral<P = UART> + 'd,
tx: impl Peripheral<P = impl OutputPin> + 'd,
rx: impl Peripheral<P = impl InputPin> + 'd,
cts: Option<impl Peripheral<P = impl InputPin> + 'd>,
rts: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: &config::Config,
) -> Result<Self, EspError> {
crate::into_ref!(uart, tx, rx);
let cts = cts.map(|cts| cts.into_ref());
let rts = rts.map(|rts| rts.into_ref());
let uart_config = uart_config_t {
baud_rate: config.baudrate.0 as i32,
data_bits: config.data_bits.into(),
@ -356,10 +328,10 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
esp!(unsafe {
uart_set_pin(
UART::port(),
pins.tx.pin(),
pins.rx.pin(),
pins.rts.as_ref().map_or(-1, |p| p.pin()),
pins.cts.as_ref().map_or(-1, |p| p.pin()),
tx.pin(),
rx.pin(),
rts.as_ref().map_or(-1, |p| p.pin()),
cts.as_ref().map_or(-1, |p| p.pin()),
)
})?;
@ -375,10 +347,9 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
})?;
Ok(Self {
uart,
pins,
rx: Rx { _uart: PhantomData },
tx: Tx { _uart: PhantomData },
_uart: uart,
rx: UartRxDriver { _uart: PhantomData },
tx: UartTxDriver { _uart: PhantomData },
})
}
@ -490,19 +461,8 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
// }
/// Split the serial driver in separate TX and RX drivers
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
(self.tx, self.rx)
}
/// Release the UART and GPIO resources
#[allow(clippy::type_complexity)]
pub fn release(self) -> Result<(UART, Pins<TX, RX, CTS, RTS>), EspError> {
esp!(unsafe { uart_driver_delete(UART::port()) })?;
// self.pins.tx.reset()?;
// self.pins.rx.reset()?;
Ok((self.uart, self.pins))
pub fn split(&mut self) -> (&mut UartTxDriver<'d, UART>, &mut UartRxDriver<'d, UART>) {
(&mut self.tx, &mut self.rx)
}
// pub fn reset_rx_fifo(&mut self) {
@ -521,15 +481,17 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
// }
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
embedded_hal::serial::ErrorType for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> Drop for UartDriver<'d, UART> {
fn drop(&mut self) {
esp!(unsafe { uart_driver_delete(UART::port()) }).unwrap();
}
}
impl<'d, UART: Uart> embedded_hal::serial::ErrorType for UartDriver<'d, UART> {
type Error = SerialError;
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
embedded_hal_0_2::serial::Read<u8> for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> embedded_hal_0_2::serial::Read<u8> for UartDriver<'d, UART> {
type Error = SerialError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
@ -537,17 +499,13 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
embedded_hal::serial::nb::Read<u8> for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> embedded_hal::serial::nb::Read<u8> for UartDriver<'d, UART> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
embedded_hal_0_2::serial::Write<u8> for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> embedded_hal_0_2::serial::Write<u8> for UartDriver<'d, UART> {
type Error = SerialError;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
@ -559,9 +517,7 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
embedded_hal::serial::nb::Write<u8> for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> embedded_hal::serial::nb::Write<u8> for UartDriver<'d, UART> {
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
@ -571,9 +527,7 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> core::fmt::Write
for Serial<UART, TX, RX, CTS, RTS>
{
impl<'d, UART: Uart> core::fmt::Write for UartDriver<'d, UART> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
use embedded_hal::serial::nb::Write;
s.as_bytes()
@ -583,11 +537,11 @@ impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> cor
}
}
impl<UART: Uart> embedded_hal::serial::ErrorType for Rx<UART> {
impl<'d, UART: Uart> embedded_hal::serial::ErrorType for UartRxDriver<'d, UART> {
type Error = SerialError;
}
impl<UART: Uart> Rx<UART> {
impl<'d, UART: Uart> UartRxDriver<'d, UART> {
/// Get count of bytes in the receive FIFO
pub fn count(&self) -> Result<u8, EspError> {
let mut size = 0_u32;
@ -638,7 +592,7 @@ impl<UART: Uart> Rx<UART> {
}
}
impl<UART: Uart> embedded_hal_0_2::serial::Read<u8> for Rx<UART> {
impl<'d, UART: Uart> embedded_hal_0_2::serial::Read<u8> for UartRxDriver<'d, UART> {
type Error = SerialError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
@ -656,7 +610,7 @@ impl<UART: Uart> embedded_hal_0_2::serial::Read<u8> for Rx<UART> {
}
}
impl<UART: Uart> embedded_hal::serial::nb::Read<u8> for Rx<UART> {
impl<'d, UART: Uart> embedded_hal::serial::nb::Read<u8> for UartRxDriver<'d, UART> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf: u8 = 0;
@ -672,7 +626,7 @@ impl<UART: Uart> embedded_hal::serial::nb::Read<u8> for Rx<UART> {
}
}
impl<UART: Uart> Tx<UART> {
impl<'d, UART: Uart> UartTxDriver<'d, UART> {
/// Write multiple bytes from a slice
pub fn write_bytes(&mut self, bytes: &[u8]) -> nb::Result<usize, SerialError> {
// `uart_write_bytes()` returns error (-1) or how many bytes were written
@ -698,11 +652,11 @@ impl<UART: Uart> Tx<UART> {
// }
}
impl<UART: Uart> embedded_hal::serial::ErrorType for Tx<UART> {
impl<'d, UART: Uart> embedded_hal::serial::ErrorType for UartTxDriver<'d, UART> {
type Error = SerialError;
}
impl<UART: Uart> embedded_hal_0_2::serial::Write<u8> for Tx<UART> {
impl<'d, UART: Uart> embedded_hal_0_2::serial::Write<u8> for UartTxDriver<'d, UART> {
type Error = SerialError;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
@ -726,7 +680,7 @@ impl<UART: Uart> embedded_hal_0_2::serial::Write<u8> for Tx<UART> {
}
}
impl<UART: Uart> embedded_hal::serial::nb::Write<u8> for Tx<UART> {
impl<'d, UART: Uart> embedded_hal::serial::nb::Write<u8> for UartTxDriver<'d, UART> {
fn flush(&mut self) -> nb::Result<(), Self::Error> {
match unsafe { uart_wait_tx_done(UART::port(), 0) } {
ESP_OK => Ok(()),
@ -748,9 +702,9 @@ impl<UART: Uart> embedded_hal::serial::nb::Write<u8> for Tx<UART> {
}
}
impl<UART: Uart> core::fmt::Write for Tx<UART>
impl<'d, UART: Uart> core::fmt::Write for UartTxDriver<'d, UART>
where
Tx<UART>: embedded_hal::serial::nb::Write<u8>,
UartTxDriver<'d, UART>: embedded_hal::serial::nb::Write<u8>,
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
use embedded_hal::serial::nb::Write;
@ -763,16 +717,7 @@ where
macro_rules! impl_uart {
($uart:ident: $port:expr) => {
pub struct $uart;
impl $uart {
/// # Safety
///
/// Care should be taken not to instantiate this UART instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
$uart {}
}
}
crate::impl_peripheral!($uart);
impl Uart for $uart {
fn port() -> uart_port_t {
@ -784,6 +729,5 @@ macro_rules! impl_uart {
impl_uart!(UART0: 0);
impl_uart!(UART1: 1);
#[cfg(esp32)]
impl_uart!(UART2: 2);

View File

@ -1,4 +1,4 @@
use core::marker::PhantomData;
use crate::peripheral::{Peripheral, PeripheralRef};
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum SleepTimer {
@ -77,18 +77,21 @@ impl Word {
}
}
pub struct ULP(PhantomData<*const ()>);
unsafe impl Send for ULP {}
impl ULP {
/// # Safety
///
/// Care should be taken not to instantiate the ULP instance, if it is already instantiated and used elsewhere
pub unsafe fn new() -> Self {
Self(PhantomData)
}
}
#[cfg(any(
all(not(esp_idf_version_major = "4"), esp_idf_ulp_coproc_enabled),
all(esp_idf_version_major = "4", esp32, esp_idf_esp32_ulp_coproc_enabled),
all(
esp_idf_version_major = "4",
esp32s2,
esp_idf_esp32s2_ulp_coproc_enabled
),
all(
esp_idf_version_major = "4",
esp32s3,
esp_idf_esp32s3_ulp_coproc_enabled
)
))]
pub struct UlpDriver<'d>(PeripheralRef<'d, ULP>);
#[cfg(any(
all(not(esp_idf_version_major = "4"), esp_idf_ulp_coproc_enabled),
@ -104,41 +107,19 @@ impl ULP {
esp_idf_esp32s3_ulp_coproc_enabled
)
))]
impl ULP {
const RTC_SLOW_MEM: u32 = 0x5000_0000_u32;
impl<'d> UlpDriver<'d> {
pub fn new(ulp: impl Peripheral<P = ULP> + 'd) -> Result<Self, esp_idf_sys::EspError> {
crate::into_ref!(ulp);
pub const MEM_START_ULP: *mut core::ffi::c_void = 0_u32 as _;
pub const MEM_START: *mut core::ffi::c_void = Self::RTC_SLOW_MEM as _;
#[cfg(all(esp32, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32_ULP_COPROC_RESERVE_MEM as _;
#[cfg(all(esp32s2, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM as _;
#[cfg(all(esp32s3, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM as _;
#[cfg(not(esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ULP_COPROC_RESERVE_MEM as _;
#[cfg(esp32)]
const TIMER_REG: *mut u32 = esp_idf_sys::RTC_CNTL_STATE0_REG as _;
#[cfg(any(esp32s2, esp32s3))]
const TIMER_REG: *mut u32 = esp_idf_sys::RTC_CNTL_ULP_CP_TIMER_REG as _;
#[cfg(any(esp32, esp32s2, esp32s3))]
const TIMER_EN_BIT: u32 =
esp_idf_sys::RTC_CNTL_ULP_CP_SLP_TIMER_EN_V << esp_idf_sys::RTC_CNTL_ULP_CP_SLP_TIMER_EN_S;
Ok(Self(ulp))
}
pub fn stop(&mut self) -> Result<(), esp_idf_sys::EspError> {
unsafe {
// disable ULP timer
core::ptr::write_volatile(
Self::TIMER_REG,
core::ptr::read_volatile(Self::TIMER_REG) & !Self::TIMER_EN_BIT,
ULP::TIMER_REG,
core::ptr::read_volatile(ULP::TIMER_REG) & !ULP::TIMER_EN_BIT,
);
// wait for at least 1 RTC_SLOW_CLK cycle
@ -150,7 +131,7 @@ impl ULP {
pub fn is_started(&self) -> Result<bool, esp_idf_sys::EspError> {
unsafe {
let enabled = (core::ptr::read_volatile(Self::TIMER_REG) & Self::TIMER_EN_BIT) != 0;
let enabled = (core::ptr::read_volatile(ULP::TIMER_REG) & ULP::TIMER_EN_BIT) != 0;
Ok(enabled)
}
@ -180,12 +161,11 @@ impl ULP {
fn check_boundaries<T>(ptr: *const T) -> Result<(), esp_idf_sys::EspError> {
let ptr = ptr as *const u8;
let mem_start = Self::MEM_START as *const u8;
let mem_start = ULP::MEM_START as *const u8;
unsafe {
if ptr < mem_start
|| ptr.offset(core::mem::size_of::<T>() as _)
> mem_start.offset(Self::MEM_SIZE as _)
|| ptr.offset(core::mem::size_of::<T>() as _) > mem_start.offset(ULP::MEM_SIZE as _)
{
esp_idf_sys::esp!(esp_idf_sys::ESP_ERR_INVALID_SIZE)?;
}
@ -215,7 +195,7 @@ impl ULP {
not(esp_idf_esp32s3_ulp_coproc_riscv)
)
))]
impl ULP {
impl<'d> UlpDriver<'d> {
pub unsafe fn load_at_ulp_address(
&mut self,
address: *mut core::ffi::c_void,
@ -240,7 +220,7 @@ impl ULP {
}
pub unsafe fn load(&mut self, program: &[u8]) -> Result<(), esp_idf_sys::EspError> {
self.load_at_ulp_address(Self::MEM_START_ULP, program)
self.load_at_ulp_address(ULP::MEM_START_ULP, program)
}
pub unsafe fn start(&mut self, address: *const u32) -> Result<(), esp_idf_sys::EspError> {
@ -316,7 +296,7 @@ impl ULP {
esp_idf_esp32s3_ulp_coproc_riscv
)
))]
impl ULP {
impl<'d> UlpDriver<'d> {
pub unsafe fn load(&mut self, program: &[u8]) -> Result<(), esp_idf_sys::EspError> {
esp_idf_sys::esp!(esp_idf_sys::ulp_riscv_load_binary(
program.as_ptr(),
@ -358,3 +338,63 @@ impl ULP {
Ok(old_value)
}
}
#[cfg(any(
all(not(esp_idf_version_major = "4"), esp_idf_ulp_coproc_enabled),
all(esp_idf_version_major = "4", esp32, esp_idf_esp32_ulp_coproc_enabled),
all(
esp_idf_version_major = "4",
esp32s2,
esp_idf_esp32s2_ulp_coproc_enabled
),
all(
esp_idf_version_major = "4",
esp32s3,
esp_idf_esp32s3_ulp_coproc_enabled
)
))]
crate::impl_peripheral!(ULP);
#[cfg(any(
all(not(esp_idf_version_major = "4"), esp_idf_ulp_coproc_enabled),
all(esp_idf_version_major = "4", esp32, esp_idf_esp32_ulp_coproc_enabled),
all(
esp_idf_version_major = "4",
esp32s2,
esp_idf_esp32s2_ulp_coproc_enabled
),
all(
esp_idf_version_major = "4",
esp32s3,
esp_idf_esp32s3_ulp_coproc_enabled
)
))]
impl ULP {
const RTC_SLOW_MEM: u32 = 0x5000_0000_u32;
pub const MEM_START_ULP: *mut core::ffi::c_void = 0_u32 as _;
pub const MEM_START: *mut core::ffi::c_void = Self::RTC_SLOW_MEM as _;
#[cfg(all(esp32, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32_ULP_COPROC_RESERVE_MEM as _;
#[cfg(all(esp32s2, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM as _;
#[cfg(all(esp32s3, esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM as _;
#[cfg(not(esp_idf_version_major = "4"))]
pub const MEM_SIZE: usize = esp_idf_sys::CONFIG_ULP_COPROC_RESERVE_MEM as _;
#[cfg(esp32)]
const TIMER_REG: *mut u32 = esp_idf_sys::RTC_CNTL_STATE0_REG as _;
#[cfg(any(esp32s2, esp32s3))]
const TIMER_REG: *mut u32 = esp_idf_sys::RTC_CNTL_ULP_CP_TIMER_REG as _;
#[cfg(any(esp32, esp32s2, esp32s3))]
const TIMER_EN_BIT: u32 =
esp_idf_sys::RTC_CNTL_ULP_CP_SLP_TIMER_EN_V << esp_idf_sys::RTC_CNTL_ULP_CP_SLP_TIMER_EN_S;
}