HAL update + CHANGELOG

This commit is contained in:
Robin Müller 2025-02-14 15:23:14 +01:00
parent f9d94a9d7e
commit 14ad647773
13 changed files with 182 additions and 119 deletions

View File

@ -32,7 +32,8 @@ use va416xx_hal::{
uart, uart,
}; };
pub type SharedUart = Mutex<CriticalSectionRawMutex, RefCell<Option<uart::RxWithIrq<pac::Uart0>>>>; pub type SharedUart =
Mutex<CriticalSectionRawMutex, RefCell<Option<uart::RxWithInterrupt<pac::Uart0>>>>;
static RX: SharedUart = Mutex::new(RefCell::new(None)); static RX: SharedUart = Mutex::new(RefCell::new(None));
const BAUDRATE: u32 = 115200; const BAUDRATE: u32 = 115200;

View File

@ -127,7 +127,7 @@ mod app {
#[local] #[local]
struct Local { struct Local {
uart_rx: uart::RxWithIrq<pac::Uart0>, uart_rx: uart::RxWithInterrupt<pac::Uart0>,
uart_tx: uart::Tx<pac::Uart0>, uart_tx: uart::Tx<pac::Uart0>,
rx_context: IrqContextTimeoutOrMaxSize, rx_context: IrqContextTimeoutOrMaxSize,
rom_spi: Option<pac::Spi3>, rom_spi: Option<pac::Spi3>,

View File

@ -8,6 +8,33 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
# [v0.4.0] 2025-02-14
## Changed
- GPIO API: Interrupt, pulse and filter and `set_datamask` and `clear_datamask` APIs are now
methods which mutable modify the pin instead of consuming and returning it.
- Simplified PWM module implementation.
- All error types now implement `core::error::Error` by using the `thiserror::Error` derive.
- `InvalidPinTypeError` now wraps the pin mode.
- I2C `TimingCfg` constructor now returns explicit error instead of generic Error.
Removed the timing configuration error type from the generic I2C error enumeration.
- `PinsA` and `PinsB` constructor do not expect an optional `pac::Ioconfig` argument anymore.
- `IrqCfg` renamed to `InterruptConfig`, kept alias for old name.
- All library provided interrupt handlers now start with common prefix `on_interrupt_*`
- `RxWithIrq` renamed to `RxWithInterrupt`
- `Rx::into_rx_with_irq` does not expect any arguments any more.
- `filter_type` renamed to `configure_filter_type`.
- `level_irq` renamed to `configure_level_interrupt`.
- `edge_irq` renamed to `configure_edge_interrupt`.
- UART interrupt management is now handled by the main constructor instead of later stages to
statically ensure one interrupt vector for the UART peripheral. `Uart::new` expects an
optional `InterruptConfig` argument.
- `enable_interrupt` and `disable_interrupt` renamed to `enable_nvic_interrupt` and
`disable_nvic_interrupt` to distinguish them from peripheral interrupts more clearly.
- `port_mux` renamed to `port_function_select`
- Renamed `IrqUartErrors` to `UartErrors`.
# [v0.3.0] 2024-30-09 # [v0.3.0] 2024-30-09
## Changed ## Changed

View File

@ -36,7 +36,7 @@ features = ["critical-section"]
[features] [features]
default = ["rt", "revb"] default = ["rt", "revb"]
rt = ["va416xx/rt"] rt = ["va416xx/rt"]
defmt = ["dep:defmt", "fugit/defmt"] defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03"]
va41630 = ["device-selected"] va41630 = ["device-selected"]
va41620 = ["device-selected"] va41620 = ["device-selected"]

View File

@ -74,34 +74,28 @@ bitflags::bitflags! {
} }
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("ADC empty error")]
pub struct AdcEmptyError; pub struct AdcEmptyError;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("invalid channel range error")]
pub struct InvalidChannelRangeError; pub struct InvalidChannelRangeError;
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[error("buffer too small")]
pub struct BufferTooSmallError; pub struct BufferTooSmallError;
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AdcRangeReadError { pub enum AdcRangeReadError {
InvalidChannelRange(InvalidChannelRangeError), #[error("invalid channel range: {0}")]
BufferTooSmall(BufferTooSmallError), InvalidChannelRange(#[from] InvalidChannelRangeError),
} #[error("buffer too small: {0}")]
BufferTooSmall(#[from] BufferTooSmallError),
impl From<InvalidChannelRangeError> for AdcRangeReadError {
fn from(value: InvalidChannelRangeError) -> Self {
AdcRangeReadError::InvalidChannelRange(value)
}
}
impl From<BufferTooSmallError> for AdcRangeReadError {
fn from(value: BufferTooSmallError) -> Self {
AdcRangeReadError::BufferTooSmall(value)
}
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]

View File

@ -19,7 +19,8 @@ use crate::time::Hertz;
pub const HBO_FREQ: Hertz = Hertz::from_raw(20_000_000); pub const HBO_FREQ: Hertz = Hertz::from_raw(20_000_000);
pub const XTAL_OSC_TSTART_MS: u32 = 15; pub const XTAL_OSC_TSTART_MS: u32 = 15;
#[derive(Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PeripheralSelect { pub enum PeripheralSelect {
Spi0 = 0, Spi0 = 0,
Spi1 = 1, Spi1 = 1,
@ -57,6 +58,7 @@ pub enum PeripheralSelect {
pub type PeripheralClock = PeripheralSelect; pub type PeripheralClock = PeripheralSelect;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FilterClkSel { pub enum FilterClkSel {
SysClk = 0, SysClk = 0,
Clk1 = 1, Clk1 = 1,

View File

@ -77,12 +77,15 @@ pub enum RPower {
Every1024 = 0b1111, Every1024 = 0b1111,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
pub struct InvalidCtrlBlockAddr; #[error("Invalid DMA control block address")]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidCtrlBlockAddrError;
bitfield::bitfield! { bitfield::bitfield! {
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ChannelConfig(u32); pub struct ChannelConfig(u32);
impl Debug; impl Debug;
u32; u32;
@ -111,6 +114,7 @@ bitfield::bitfield! {
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DmaChannelControl { pub struct DmaChannelControl {
pub src_end_ptr: u32, pub src_end_ptr: u32,
pub dest_end_ptr: u32, pub dest_end_ptr: u32,
@ -160,9 +164,9 @@ impl DmaCtrlBlock {
/// The passed address must be 128-byte aligned. The user must also take care of specifying /// The passed address must be 128-byte aligned. The user must also take care of specifying
/// a valid memory address for the DMA control block which is accessible by the system as well. /// a valid memory address for the DMA control block which is accessible by the system as well.
/// For example, the control block can be placed in the SRAM1. /// For example, the control block can be placed in the SRAM1.
pub fn new_at_addr(addr: u32) -> Result<*mut DmaCtrlBlock, InvalidCtrlBlockAddr> { pub fn new_at_addr(addr: u32) -> Result<*mut DmaCtrlBlock, InvalidCtrlBlockAddrError> {
if addr & BASE_PTR_ADDR_MASK > 0 { if addr & BASE_PTR_ADDR_MASK > 0 {
return Err(InvalidCtrlBlockAddr); return Err(InvalidCtrlBlockAddrError);
} }
let ctrl_block_ptr = addr as *mut DmaCtrlBlock; let ctrl_block_ptr = addr as *mut DmaCtrlBlock;
unsafe { core::ptr::write(ctrl_block_ptr, DmaCtrlBlock::default()) } unsafe { core::ptr::write(ctrl_block_ptr, DmaCtrlBlock::default()) }
@ -175,19 +179,21 @@ pub struct Dma {
ctrl_block: *mut DmaCtrlBlock, ctrl_block: *mut DmaCtrlBlock,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DmaTransferInitError { pub enum DmaTransferInitError {
SourceDestLenMissmatch { #[error("source and destination buffer length mismatch: {src_len} != {dest_len}")]
src_len: usize, SourceDestLenMissmatch { src_len: usize, dest_len: usize },
dest_len: usize,
},
/// Overflow when calculating the source or destination end address. /// Overflow when calculating the source or destination end address.
#[error("address overflow")]
AddrOverflow, AddrOverflow,
/// Transfer size larger than 1024 units. /// Transfer size larger than 1024 units.
#[error("transfer size too large: {0}, 1024 is the allowed maximum")]
TransferSizeTooLarge(usize), TransferSizeTooLarge(usize),
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DmaCfg { pub struct DmaCfg {
pub bufferable: bool, pub bufferable: bool,
pub cacheable: bool, pub cacheable: bool,
@ -493,11 +499,11 @@ impl Dma {
dma: pac::Dma, dma: pac::Dma,
cfg: DmaCfg, cfg: DmaCfg,
ctrl_block: *mut DmaCtrlBlock, ctrl_block: *mut DmaCtrlBlock,
) -> Result<Self, InvalidCtrlBlockAddr> { ) -> Result<Self, InvalidCtrlBlockAddrError> {
// The conversion to u32 is safe here because we are on a 32-bit system. // The conversion to u32 is safe here because we are on a 32-bit system.
let raw_addr = ctrl_block as u32; let raw_addr = ctrl_block as u32;
if raw_addr & BASE_PTR_ADDR_MASK > 0 { if raw_addr & BASE_PTR_ADDR_MASK > 0 {
return Err(InvalidCtrlBlockAddr); return Err(InvalidCtrlBlockAddrError);
} }
syscfg.enable_peripheral_clock(PeripheralClock::Dma); syscfg.enable_peripheral_clock(PeripheralClock::Dma);
syscfg.assert_periph_reset_for_two_cycles(PeripheralSelect::Dma); syscfg.assert_periph_reset_for_two_cycles(PeripheralSelect::Dma);

View File

@ -68,7 +68,7 @@ use super::{
/// Value-level `enum` for disabled configurations /// Value-level `enum` for disabled configurations
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynDisabled { pub enum DynDisabled {
Floating, Floating,
PullDown, PullDown,
@ -77,7 +77,7 @@ pub enum DynDisabled {
/// Value-level `enum` for input configurations /// Value-level `enum` for input configurations
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynInput { pub enum DynInput {
Floating, Floating,
PullDown, PullDown,
@ -86,7 +86,7 @@ pub enum DynInput {
/// Value-level `enum` for output configurations /// Value-level `enum` for output configurations
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynOutput { pub enum DynOutput {
PushPull, PushPull,
OpenDrain, OpenDrain,
@ -121,7 +121,7 @@ impl embedded_hal::digital::Error for InvalidPinTypeError {
/// Value-level `enum` representing pin modes /// Value-level `enum` representing pin modes
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynPinMode { pub enum DynPinMode {
Input(DynInput), Input(DynInput),
Output(DynOutput), Output(DynOutput),
@ -157,7 +157,7 @@ pub const DYN_ALT_FUNC_3: DynPinMode = DynPinMode::Alternate(DynAlternate::Sel3)
/// Value-level `enum` for pin groups /// Value-level `enum` for pin groups
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DynGroup { pub enum DynGroup {
A, A,
B, B,
@ -170,7 +170,7 @@ pub enum DynGroup {
/// Value-level `struct` representing pin IDs /// Value-level `struct` representing pin IDs
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DynPinId { pub struct DynPinId {
pub group: DynGroup, pub group: DynGroup,
pub num: u8, pub num: u8,
@ -185,7 +185,7 @@ pub struct DynPinId {
/// This `struct` takes ownership of a [`DynPinId`] and provides an API to /// This `struct` takes ownership of a [`DynPinId`] and provides an API to
/// access the corresponding regsiters. /// access the corresponding regsiters.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct DynRegisters(DynPinId); pub(crate) struct DynRegisters(DynPinId);
// [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`] // [`DynRegisters`] takes ownership of the [`DynPinId`], and [`DynPin`]
@ -219,7 +219,7 @@ impl DynRegisters {
/// This type acts as a type-erased version of [`Pin`]. Every pin is represented /// This type acts as a type-erased version of [`Pin`]. Every pin is represented
/// by the same type, and pins are tracked and distinguished at run-time. /// by the same type, and pins are tracked and distinguished at run-time.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DynPin { pub struct DynPin {
pub(crate) regs: DynRegisters, pub(crate) regs: DynRegisters,
mode: DynPinMode, mode: DynPinMode,

View File

@ -28,37 +28,42 @@ pub enum FifoEmptyMode {
EndTransaction = 1, EndTransaction = 1,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClockTooSlowForFastI2c; #[error("clock too slow for fast I2C mode")]
pub struct ClockTooSlowForFastI2cError;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[error("invalid timing parameters")]
pub struct InvalidTimingParamsError;
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
InvalidTimingParams, #[error("arbitration lost")]
ArbitrationLost, ArbitrationLost,
#[error("nack address")]
NackAddr, NackAddr,
/// Data not acknowledged in write operation /// Data not acknowledged in write operation
#[error("data not acknowledged in write operation")]
NackData, NackData,
/// Not enough data received in read operation /// Not enough data received in read operation
#[error("insufficient data received")]
InsufficientDataReceived, InsufficientDataReceived,
/// Number of bytes in transfer too large (larger than 0x7fe) /// Number of bytes in transfer too large (larger than 0x7fe)
#[error("data too large (larger than 0x7fe)")]
DataTooLarge, DataTooLarge,
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum InitError { pub enum InitError {
/// Wrong address used in constructor /// Wrong address used in constructor
#[error("wrong address mode")]
WrongAddrMode, WrongAddrMode,
/// APB1 clock is too slow for fast I2C mode. /// APB1 clock is too slow for fast I2C mode.
ClkTooSlow(ClockTooSlowForFastI2c), #[error("clock too slow for fast I2C mode: {0}")]
} ClkTooSlow(#[from] ClockTooSlowForFastI2cError),
impl From<ClockTooSlowForFastI2c> for InitError {
fn from(value: ClockTooSlowForFastI2c) -> Self {
Self::ClkTooSlow(value)
}
} }
impl embedded_hal::i2c::Error for Error { impl embedded_hal::i2c::Error for Error {
@ -71,7 +76,7 @@ impl embedded_hal::i2c::Error for Error {
Error::NackData => { Error::NackData => {
embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data)
} }
Error::DataTooLarge | Error::InsufficientDataReceived | Error::InvalidTimingParams => { Error::DataTooLarge | Error::InsufficientDataReceived => {
embedded_hal::i2c::ErrorKind::Other embedded_hal::i2c::ErrorKind::Other
} }
} }
@ -153,9 +158,12 @@ impl Instance for pac::I2c2 {
// Config // Config
//================================================================================================== //==================================================================================================
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TrTfThighTlow(u8, u8, u8, u8); pub struct TrTfThighTlow(u8, u8, u8, u8);
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TsuStoTsuStaThdStaTBuf(u8, u8, u8, u8); pub struct TsuStoTsuStaThdStaTBuf(u8, u8, u8, u8);
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TimingCfg { pub struct TimingCfg {
// 4 bit max width // 4 bit max width
tr: u8, tr: u8,
@ -179,7 +187,7 @@ impl TimingCfg {
pub fn new( pub fn new(
first_16_bits: TrTfThighTlow, first_16_bits: TrTfThighTlow,
second_16_bits: TsuStoTsuStaThdStaTBuf, second_16_bits: TsuStoTsuStaThdStaTBuf,
) -> Result<Self, Error> { ) -> Result<Self, InvalidTimingParamsError> {
if first_16_bits.0 > 0xf if first_16_bits.0 > 0xf
|| first_16_bits.1 > 0xf || first_16_bits.1 > 0xf
|| first_16_bits.2 > 0xf || first_16_bits.2 > 0xf
@ -189,7 +197,7 @@ impl TimingCfg {
|| second_16_bits.2 > 0xf || second_16_bits.2 > 0xf
|| second_16_bits.3 > 0xf || second_16_bits.3 > 0xf
{ {
return Err(Error::InvalidTimingParams); return Err(InvalidTimingParamsError);
} }
Ok(TimingCfg { Ok(TimingCfg {
tr: first_16_bits.0, tr: first_16_bits.0,
@ -230,6 +238,7 @@ impl Default for TimingCfg {
} }
} }
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct MasterConfig { pub struct MasterConfig {
pub tx_fe_mode: FifoEmptyMode, pub tx_fe_mode: FifoEmptyMode,
pub rx_fe_mode: FifoEmptyMode, pub rx_fe_mode: FifoEmptyMode,
@ -256,6 +265,8 @@ impl Default for MasterConfig {
impl Sealed for MasterConfig {} impl Sealed for MasterConfig {}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SlaveConfig { pub struct SlaveConfig {
pub tx_fe_mode: FifoEmptyMode, pub tx_fe_mode: FifoEmptyMode,
pub rx_fe_mode: FifoEmptyMode, pub rx_fe_mode: FifoEmptyMode,
@ -318,7 +329,7 @@ impl<I2c: Instance> I2cBase<I2c> {
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
ms_cfg: Option<&MasterConfig>, ms_cfg: Option<&MasterConfig>,
sl_cfg: Option<&SlaveConfig>, sl_cfg: Option<&SlaveConfig>,
) -> Result<Self, ClockTooSlowForFastI2c> { ) -> Result<Self, ClockTooSlowForFastI2cError> {
syscfg.enable_peripheral_clock(I2c::PERIPH_SEL); syscfg.enable_peripheral_clock(I2c::PERIPH_SEL);
let mut i2c_base = I2cBase { let mut i2c_base = I2cBase {
@ -421,19 +432,22 @@ impl<I2c: Instance> I2cBase<I2c> {
}); });
} }
fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2c> { fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result<u8, ClockTooSlowForFastI2cError> {
if speed_mode == I2cSpeed::Regular100khz { if speed_mode == I2cSpeed::Regular100khz {
Ok(((self.clock.raw() / CLK_100K.raw() / 20) - 1) as u8) Ok(((self.clock.raw() / CLK_100K.raw() / 20) - 1) as u8)
} else { } else {
if self.clock.raw() < MIN_CLK_400K.raw() { if self.clock.raw() < MIN_CLK_400K.raw() {
return Err(ClockTooSlowForFastI2c); return Err(ClockTooSlowForFastI2cError);
} }
Ok(((self.clock.raw() / CLK_400K.raw() / 25) - 1) as u8) Ok(((self.clock.raw() / CLK_400K.raw() / 25) - 1) as u8)
} }
} }
/// Configures the clock scale for a given speed mode setting /// Configures the clock scale for a given speed mode setting
pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2c> { pub fn cfg_clk_scale(
&mut self,
speed_mode: I2cSpeed,
) -> Result<(), ClockTooSlowForFastI2cError> {
let clk_div = self.calc_clk_div(speed_mode)?; let clk_div = self.calc_clk_div(speed_mode)?;
self.i2c self.i2c
.clkscale() .clkscale()
@ -472,7 +486,7 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
cfg: MasterConfig, cfg: MasterConfig,
clocks: &Clocks, clocks: &Clocks,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
) -> Result<Self, ClockTooSlowForFastI2c> { ) -> Result<Self, ClockTooSlowForFastI2cError> {
Ok(I2cMaster { Ok(I2cMaster {
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, Some(&cfg), None)?, i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, Some(&cfg), None)?,
addr: PhantomData, addr: PhantomData,
@ -733,7 +747,7 @@ impl<I2c: Instance, Addr> I2cSlave<I2c, Addr> {
cfg: SlaveConfig, cfg: SlaveConfig,
clocks: &Clocks, clocks: &Clocks,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
) -> Result<Self, ClockTooSlowForFastI2c> { ) -> Result<Self, ClockTooSlowForFastI2cError> {
Ok(I2cSlave { Ok(I2cSlave {
i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, None, Some(&cfg))?, i2c_base: I2cBase::new(i2c, sys_cfg, clocks, speed_mode, None, Some(&cfg))?,
addr: PhantomData, addr: PhantomData,
@ -895,7 +909,7 @@ impl<I2c: Instance> I2cSlave<I2c, TenBitAddress> {
cfg: SlaveConfig, cfg: SlaveConfig,
clocks: &Clocks, clocks: &Clocks,
speed_mode: I2cSpeed, speed_mode: I2cSpeed,
) -> Result<Self, ClockTooSlowForFastI2c> { ) -> Result<Self, ClockTooSlowForFastI2cError> {
Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode) Self::new_generic(i2c, sys_cfg, cfg, clocks, speed_mode)
} }
} }

View File

@ -63,6 +63,7 @@ pub mod adc;
pub mod dac; pub mod dac;
#[derive(Debug, Eq, Copy, Clone, PartialEq)] #[derive(Debug, Eq, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FunSel { pub enum FunSel {
Sel0 = 0b00, Sel0 = 0b00,
Sel1 = 0b01, Sel1 = 0b01,

View File

@ -39,6 +39,7 @@ pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
pub const BMSKIPDATA_MASK: u32 = 1 << 30; pub const BMSKIPDATA_MASK: u32 = 1 << 30;
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum HwChipSelectId { pub enum HwChipSelectId {
Id0 = 0, Id0 = 0,
Id1 = 1, Id1 = 1,
@ -52,6 +53,7 @@ pub enum HwChipSelectId {
} }
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiId { pub enum SpiId {
Spi0, Spi0,
Spi1, Spi1,
@ -61,6 +63,7 @@ pub enum SpiId {
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize { pub enum WordSize {
OneBit = 0x00, OneBit = 0x00,
FourBits = 0x03, FourBits = 0x03,
@ -68,6 +71,57 @@ pub enum WordSize {
SixteenBits = 0x0f, SixteenBits = 0x0f,
} }
pub type SpiRegBlock = pac::spi0::RegisterBlock;
/// Common trait implemented by all PAC peripheral access structures. The register block
/// format is the same for all SPI blocks.
pub trait Instance: Deref<Target = SpiRegBlock> {
const IDX: u8;
const PERIPH_SEL: PeripheralSelect;
fn ptr() -> *const SpiRegBlock;
}
impl Instance for pac::Spi0 {
const IDX: u8 = 0;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi1 {
const IDX: u8 = 1;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi2 {
const IDX: u8 = 2;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi3 {
const IDX: u8 = 3;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi3;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
//================================================================================================== //==================================================================================================
// Pin type definitions // Pin type definitions
//================================================================================================== //==================================================================================================
@ -239,6 +293,7 @@ pub trait TransferConfigProvider {
/// This struct contains all configuration parameter which are transfer specific /// This struct contains all configuration parameter which are transfer specific
/// and might change for transfers to different SPI slaves /// and might change for transfers to different SPI slaves
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferConfigWithHwcs<HwCs> { pub struct TransferConfigWithHwcs<HwCs> {
pub hw_cs: Option<HwCs>, pub hw_cs: Option<HwCs>,
pub cfg: TransferConfig, pub cfg: TransferConfig,
@ -247,6 +302,7 @@ pub struct TransferConfigWithHwcs<HwCs> {
/// Type erased variant of the transfer configuration. This is required to avoid generics in /// Type erased variant of the transfer configuration. This is required to avoid generics in
/// the SPI constructor. /// the SPI constructor.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferConfig { pub struct TransferConfig {
pub clk_cfg: Option<SpiClkConfig>, pub clk_cfg: Option<SpiClkConfig>,
pub mode: Option<Mode>, pub mode: Option<Mode>,
@ -334,6 +390,8 @@ impl<HwCs: HwCsProvider> TransferConfigProvider for TransferConfigWithHwcs<HwCs>
} }
/// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details /// Configuration options for the whole SPI bus. See Programmer Guide p.92 for more details
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SpiConfig { pub struct SpiConfig {
clk: SpiClkConfig, clk: SpiClkConfig,
// SPI mode configuration // SPI mode configuration
@ -432,57 +490,6 @@ impl WordProvider for u16 {
} }
} }
pub type SpiRegBlock = pac::spi0::RegisterBlock;
/// Common trait implemented by all PAC peripheral access structures. The register block
/// format is the same for all SPI blocks.
pub trait Instance: Deref<Target = SpiRegBlock> {
const IDX: u8;
const PERIPH_SEL: PeripheralSelect;
fn ptr() -> *const SpiRegBlock;
}
impl Instance for pac::Spi0 {
const IDX: u8 = 0;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi0;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi1 {
const IDX: u8 = 1;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi1;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi2 {
const IDX: u8 = 2;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi2;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
impl Instance for pac::Spi3 {
const IDX: u8 = 3;
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Spi3;
#[inline(always)]
fn ptr() -> *const SpiRegBlock {
Self::ptr()
}
}
//================================================================================================== //==================================================================================================
// Spi // Spi
//================================================================================================== //==================================================================================================
@ -533,6 +540,7 @@ pub struct Spi<SpiInstance, Pins, Word = u8> {
pins: Pins, pins: Pins,
} }
#[inline(always)]
pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) { pub fn mode_to_cpo_cph_bit(mode: embedded_hal::spi::Mode) -> (bool, bool) {
match mode { match mode {
embedded_hal::spi::MODE_0 => (false, false), embedded_hal::spi::MODE_0 => (false, false),
@ -575,10 +583,14 @@ impl SpiClkConfig {
} }
} }
#[derive(Debug)] #[derive(Debug, thiserror::Error)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiClkConfigError { pub enum SpiClkConfigError {
#[error("division by zero")]
DivIsZero, DivIsZero,
#[error("divide value is not even")]
DivideValueNotEven, DivideValueNotEven,
#[error("scrdv value is too large")]
ScrdvValueTooLarge, ScrdvValueTooLarge,
} }

View File

@ -78,6 +78,7 @@ pub const unsafe fn get_tim_raw(tim_idx: usize) -> &'static pac::tim0::RegisterB
//================================================================================================== //==================================================================================================
#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] #[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CascadeCtrl { pub struct CascadeCtrl {
/// Enable Cascade 0 signal active as a requirement for counting /// Enable Cascade 0 signal active as a requirement for counting
pub enb_start_src_csd0: bool, pub enb_start_src_csd0: bool,

View File

@ -248,6 +248,7 @@ impl From<Hertz> for Config {
//================================================================================================== //==================================================================================================
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IrqContextTimeoutOrMaxSize { pub struct IrqContextTimeoutOrMaxSize {
rx_idx: usize, rx_idx: usize,
mode: IrqReceptionMode, mode: IrqReceptionMode,
@ -273,6 +274,7 @@ impl IrqContextTimeoutOrMaxSize {
/// This struct is used to return the default IRQ handler result to the user /// This struct is used to return the default IRQ handler result to the user
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IrqResult { pub struct IrqResult {
pub bytes_read: usize, pub bytes_read: usize,
pub errors: Option<UartErrors>, pub errors: Option<UartErrors>,
@ -280,6 +282,7 @@ pub struct IrqResult {
/// This struct is used to return the default IRQ handler result to the user /// This struct is used to return the default IRQ handler result to the user
#[derive(Debug, Default)] #[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IrqResultMaxSizeOrTimeout { pub struct IrqResultMaxSizeOrTimeout {
complete: bool, complete: bool,
timeout: bool, timeout: bool,
@ -330,12 +333,14 @@ impl IrqResultMaxSizeOrTimeout {
} }
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum IrqReceptionMode { enum IrqReceptionMode {
Idle, Idle,
Pending, Pending,
} }
#[derive(Default, Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UartErrors { pub struct UartErrors {
overflow: bool, overflow: bool,
framing: bool, framing: bool,
@ -780,8 +785,8 @@ impl<Uart: Instance> Rx<Uart> {
self.0.data().read().bits() self.0.data().read().bits()
} }
pub fn into_rx_with_irq(self) -> RxWithIrq<Uart> { pub fn into_rx_with_irq(self) -> RxWithInterrupt<Uart> {
RxWithIrq(self) RxWithInterrupt(self)
} }
pub fn release(self) -> Uart { pub fn release(self) -> Uart {
@ -962,9 +967,9 @@ impl<Uart: Instance> embedded_io::Write for Tx<Uart> {
/// then call the [Self::irq_handler_max_size_or_timeout_based] in the interrupt service /// then call the [Self::irq_handler_max_size_or_timeout_based] in the interrupt service
/// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to /// routine. You have to call [Self::read_fixed_len_or_timeout_based_using_irq] in the ISR to
/// start reading the next packet. /// start reading the next packet.
pub struct RxWithIrq<Uart>(Rx<Uart>); pub struct RxWithInterrupt<Uart>(Rx<Uart>);
impl<Uart: Instance> RxWithIrq<Uart> { impl<Uart: Instance> RxWithInterrupt<Uart> {
/// This function should be called once at initialization time if the regular /// This function should be called once at initialization time if the regular
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver. /// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
pub fn start(&mut self) { pub fn start(&mut self) {