HAL update
This commit is contained in:
parent
6cbba8414c
commit
bf41b59a24
@ -122,14 +122,14 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
TestCase::Pulse => {
|
TestCase::Pulse => {
|
||||||
let mut output_pulsed = pinsa.pa0.into_push_pull_output();
|
let mut output_pulsed = pinsa.pa0.into_push_pull_output();
|
||||||
output_pulsed.pulse_mode(true, PinState::Low);
|
output_pulsed.configure_pulse_mode(true, PinState::Low);
|
||||||
rprintln!("Pulsing high 10 times..");
|
rprintln!("Pulsing high 10 times..");
|
||||||
output_pulsed.set_low().unwrap();
|
output_pulsed.set_low().unwrap();
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
output_pulsed.set_high().unwrap();
|
output_pulsed.set_high().unwrap();
|
||||||
cortex_m::asm::delay(25_000_000);
|
cortex_m::asm::delay(25_000_000);
|
||||||
}
|
}
|
||||||
output_pulsed.pulse_mode(true, PinState::High);
|
output_pulsed.configure_pulse_mode(true, PinState::High);
|
||||||
rprintln!("Pulsing low 10 times..");
|
rprintln!("Pulsing low 10 times..");
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
output_pulsed.set_low().unwrap();
|
output_pulsed.set_low().unwrap();
|
||||||
@ -137,15 +137,12 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TestCase::DelayGpio => {
|
TestCase::DelayGpio => {
|
||||||
let mut out_0 = pinsa
|
let mut out_0 = pinsa.pa0.into_readable_push_pull_output();
|
||||||
.pa0
|
out_0.configure_delay(true, false);
|
||||||
.into_readable_push_pull_output()
|
let mut out_1 = pinsa.pa1.into_readable_push_pull_output();
|
||||||
.delay(true, false);
|
out_1.configure_delay(false, true);
|
||||||
let mut out_1 = pinsa
|
let mut out_2 = pinsa.pa3.into_readable_push_pull_output();
|
||||||
.pa1
|
out_2.configure_delay(true, true);
|
||||||
.into_readable_push_pull_output()
|
|
||||||
.delay(false, true);
|
|
||||||
let mut out_2 = pinsa.pa3.into_readable_push_pull_output().delay(true, true);
|
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
out_0.toggle().unwrap();
|
out_0.toggle().unwrap();
|
||||||
out_1.toggle().unwrap();
|
out_1.toggle().unwrap();
|
||||||
|
@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [unreleased]
|
## [unreleased]
|
||||||
|
|
||||||
|
## [v0.10.0]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- A lot of missing `defmt::Format` implementations.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Missing GPIO API replacements from `x` to `configure_x`
|
||||||
|
|
||||||
## [v0.9.0]
|
## [v0.9.0]
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
@ -29,7 +29,7 @@ static_cell = "2"
|
|||||||
thiserror = { version = "2", default-features = false }
|
thiserror = { version = "2", default-features = false }
|
||||||
void = { version = "1", default-features = false }
|
void = { version = "1", default-features = false }
|
||||||
once_cell = {version = "1", default-features = false }
|
once_cell = {version = "1", default-features = false }
|
||||||
va108xx = { version = "0.4", default-features = false, features = ["critical-section"] }
|
va108xx = { version = "0.5", path = "../va108xx", default-features = false, features = ["critical-section", "defmt"] }
|
||||||
embassy-sync = "0.6"
|
embassy-sync = "0.6"
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
@ -42,7 +42,7 @@ portable-atomic = "1"
|
|||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
rt = ["va108xx/rt"]
|
rt = ["va108xx/rt"]
|
||||||
defmt = ["dep:defmt", "fugit/defmt"]
|
defmt = ["dep:defmt", "fugit/defmt", "embedded-hal/defmt-03"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
@ -115,7 +115,7 @@ impl InputPinFuture {
|
|||||||
|
|
||||||
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
EDGE_DETECTION[pin_id_to_offset(pin.id())]
|
||||||
.store(false, core::sync::atomic::Ordering::Relaxed);
|
.store(false, core::sync::atomic::Ordering::Relaxed);
|
||||||
pin.interrupt_edge(
|
pin.configure_edge_interrupt(
|
||||||
edge,
|
edge,
|
||||||
InterruptConfig::new(irq, true, true),
|
InterruptConfig::new(irq, true, true),
|
||||||
Some(sys_cfg),
|
Some(sys_cfg),
|
||||||
|
@ -181,6 +181,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))]
|
||||||
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`]
|
||||||
@ -392,11 +393,15 @@ impl DynPin {
|
|||||||
/// - Delay 2: 2
|
/// - Delay 2: 2
|
||||||
/// - Delay 1 + Delay 2: 3
|
/// - Delay 1 + Delay 2: 3
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn delay(self, delay_1: bool, delay_2: bool) -> Result<Self, InvalidPinTypeError> {
|
pub fn configure_delay(
|
||||||
|
&mut self,
|
||||||
|
delay_1: bool,
|
||||||
|
delay_2: bool,
|
||||||
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Output(_) => {
|
DynPinMode::Output(_) => {
|
||||||
self.regs.delay(delay_1, delay_2);
|
self.regs.configure_delay(delay_1, delay_2);
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(self.mode)),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
}
|
}
|
||||||
@ -406,7 +411,7 @@ impl DynPin {
|
|||||||
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
/// one clock cycle before returning to the configured default state
|
/// one clock cycle before returning to the configured default state
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pulse_mode(
|
pub fn configure_pulse_mode(
|
||||||
&mut self,
|
&mut self,
|
||||||
enable: bool,
|
enable: bool,
|
||||||
default_state: PinState,
|
default_state: PinState,
|
||||||
@ -422,14 +427,14 @@ impl DynPin {
|
|||||||
|
|
||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn filter_type(
|
pub fn configure_filter_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
filter: FilterType,
|
filter: FilterType,
|
||||||
clksel: FilterClkSel,
|
clksel: FilterClkSel,
|
||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) => {
|
DynPinMode::Input(_) => {
|
||||||
self.regs.filter_type(filter, clksel);
|
self.regs.configure_filter_type(filter, clksel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => Err(InvalidPinTypeError(self.mode)),
|
_ => Err(InvalidPinTypeError(self.mode)),
|
||||||
@ -437,7 +442,7 @@ impl DynPin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn interrupt_edge(
|
pub fn configure_edge_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
@ -446,7 +451,7 @@ impl DynPin {
|
|||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_edge(edge_type);
|
self.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -455,7 +460,7 @@ impl DynPin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn interrupt_level(
|
pub fn configure_level_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
@ -464,7 +469,7 @@ impl DynPin {
|
|||||||
) -> Result<(), InvalidPinTypeError> {
|
) -> Result<(), InvalidPinTypeError> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
DynPinMode::Input(_) | DynPinMode::Output(_) => {
|
||||||
self.regs.interrupt_level(level_type);
|
self.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ use paste::paste;
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptEdge {
|
pub enum InterruptEdge {
|
||||||
HighToLow,
|
HighToLow,
|
||||||
LowToHigh,
|
LowToHigh,
|
||||||
@ -96,12 +97,14 @@ pub enum InterruptEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptLevel {
|
pub enum InterruptLevel {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PinState {
|
pub enum PinState {
|
||||||
Low = 0,
|
Low = 0,
|
||||||
High = 1,
|
High = 1,
|
||||||
@ -353,6 +356,7 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn id(&self) -> DynPinId {
|
pub fn id(&self) -> DynPinId {
|
||||||
self.inner.id()
|
self.inner.id()
|
||||||
}
|
}
|
||||||
@ -482,11 +486,6 @@ impl<I: PinId, M: PinMode> Pin<I, M> {
|
|||||||
self.inner.regs.write_pin(false)
|
self.inner.regs.write_pin(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn _toggle_with_toggle_reg(&mut self) {
|
|
||||||
self.inner.regs.toggle();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _is_low(&self) -> bool {
|
pub(crate) fn _is_low(&self) -> bool {
|
||||||
!self.inner.regs.read_pin()
|
!self.inner.regs.read_pin()
|
||||||
@ -599,7 +598,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,7 +609,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_level(level_type);
|
self.inner.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,23 +621,34 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
/// - Delay 2: 2
|
/// - Delay 2: 2
|
||||||
/// - Delay 1 + Delay 2: 3
|
/// - Delay 1 + Delay 2: 3
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn delay(self, delay_1: bool, delay_2: bool) -> Self {
|
pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
|
||||||
self.inner.regs.delay(delay_1, delay_2);
|
self.inner.regs.configure_delay(delay_1, delay_2);
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn toggle_with_toggle_reg(&mut self) {
|
pub fn toggle_with_toggle_reg(&mut self) {
|
||||||
self._toggle_with_toggle_reg()
|
self.inner.regs.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_pulse_mode` method instead"
|
||||||
|
)]
|
||||||
|
pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
||||||
|
self.configure_pulse_mode(enable, default_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See p.52 of the programmers guide for more information.
|
/// See p.52 of the programmers guide for more information.
|
||||||
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
/// When configured for pulse mode, a given pin will set the non-default state for exactly
|
||||||
/// one clock cycle before returning to the configured default state
|
/// one clock cycle before returning to the configured default state
|
||||||
pub fn pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
|
||||||
self.inner.regs.pulse_mode(enable, default_state);
|
self.inner.regs.pulse_mode(enable, default_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_edge_interrupt` method instead"
|
||||||
|
)]
|
||||||
pub fn interrupt_edge(
|
pub fn interrupt_edge(
|
||||||
&mut self,
|
&mut self,
|
||||||
edge_type: InterruptEdge,
|
edge_type: InterruptEdge,
|
||||||
@ -646,18 +656,43 @@ impl<I: PinId, C: OutputConfig> Pin<I, Output<C>> {
|
|||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_edge(edge_type);
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interrupt_level(
|
pub fn configure_edge_interrupt(
|
||||||
|
&mut self,
|
||||||
|
edge_type: InterruptEdge,
|
||||||
|
irq_cfg: InterruptConfig,
|
||||||
|
syscfg: Option<&mut Sysconfig>,
|
||||||
|
irqsel: Option<&mut Irqsel>,
|
||||||
|
) {
|
||||||
|
self.inner.regs.configure_edge_interrupt(edge_type);
|
||||||
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.9.0",
|
||||||
|
note = "Please use the `configure_level_interrupt` method instead"
|
||||||
|
)]
|
||||||
|
pub fn level_interrupt(
|
||||||
&mut self,
|
&mut self,
|
||||||
level_type: InterruptLevel,
|
level_type: InterruptLevel,
|
||||||
irq_cfg: InterruptConfig,
|
irq_cfg: InterruptConfig,
|
||||||
syscfg: Option<&mut Sysconfig>,
|
syscfg: Option<&mut Sysconfig>,
|
||||||
irqsel: Option<&mut Irqsel>,
|
irqsel: Option<&mut Irqsel>,
|
||||||
) {
|
) {
|
||||||
self.inner.regs.interrupt_level(level_type);
|
self.configure_level_interrupt(level_type, irq_cfg, syscfg, irqsel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_level_interrupt(
|
||||||
|
&mut self,
|
||||||
|
level_type: InterruptLevel,
|
||||||
|
irq_cfg: InterruptConfig,
|
||||||
|
syscfg: Option<&mut Sysconfig>,
|
||||||
|
irqsel: Option<&mut Irqsel>,
|
||||||
|
) {
|
||||||
|
self.inner.regs.configure_level_interrupt(level_type);
|
||||||
self.irq_enb(irq_cfg, syscfg, irqsel);
|
self.irq_enb(irq_cfg, syscfg, irqsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,7 +701,7 @@ impl<I: PinId, C: InputConfig> Pin<I, Input<C>> {
|
|||||||
/// See p.37 and p.38 of the programmers guide for more information.
|
/// See p.37 and p.38 of the programmers guide for more information.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.inner.regs.filter_type(filter, clksel);
|
self.inner.regs.configure_filter_type(filter, clksel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
|
/// Only useful for interrupt pins. Configure whether to use edges or level as interrupt soure
|
||||||
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
/// When using edge mode, it is possible to generate interrupts on both edges as well
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_edge(&mut self, edge_type: InterruptEdge) {
|
fn configure_edge_interrupt(&mut self, edge_type: InterruptEdge) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -267,7 +267,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Configure which edge or level type triggers an interrupt
|
/// Configure which edge or level type triggers an interrupt
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interrupt_level(&mut self, level: InterruptLevel) {
|
fn configure_level_interrupt(&mut self, level: InterruptLevel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.port_reg()
|
self.port_reg()
|
||||||
.irq_sen()
|
.irq_sen()
|
||||||
@ -286,7 +286,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
|
|
||||||
/// Only useful for input pins
|
/// Only useful for input pins
|
||||||
#[inline]
|
#[inline]
|
||||||
fn filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
|
||||||
self.iocfg_port().modify(|_, w| {
|
self.iocfg_port().modify(|_, w| {
|
||||||
// Safety: Only write to register for this Pin ID
|
// Safety: Only write to register for this Pin ID
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -349,7 +349,7 @@ pub(super) unsafe trait RegisterInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Only useful for output pins
|
/// Only useful for output pins
|
||||||
fn delay(&self, delay_1: bool, delay_2: bool) {
|
fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
|
||||||
let portreg = self.port_reg();
|
let portreg = self.port_reg();
|
||||||
unsafe {
|
unsafe {
|
||||||
if delay_1 {
|
if delay_1 {
|
||||||
|
@ -36,8 +36,6 @@ pub struct InvalidTimingParamsError;
|
|||||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
#[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 {
|
||||||
//#[error("Invalid timing parameters")]
|
|
||||||
//InvalidTimingParams,
|
|
||||||
#[error("arbitration lost")]
|
#[error("arbitration lost")]
|
||||||
ArbitrationLost,
|
ArbitrationLost,
|
||||||
#[error("nack address")]
|
#[error("nack address")]
|
||||||
@ -82,6 +80,7 @@ impl embedded_hal::i2c::Error for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
enum I2cCmd {
|
enum I2cCmd {
|
||||||
Start = 0b00,
|
Start = 0b00,
|
||||||
Stop = 0b10,
|
Stop = 0b10,
|
||||||
@ -252,6 +251,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,
|
||||||
@ -455,13 +456,6 @@ impl<I2c: Instance> I2cBase<I2c> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique mode to use the loopback functionality
|
|
||||||
// pub struct I2cLoopback<I2C> {
|
|
||||||
// i2c_base: I2cBase<I2C>,
|
|
||||||
// master_cfg: MasterConfig,
|
|
||||||
// slave_cfg: SlaveConfig,
|
|
||||||
// }
|
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// I2C Master
|
// I2C Master
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
@ -673,275 +667,6 @@ impl<I2c: Instance, Addr> I2cMaster<I2c, Addr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
macro_rules! i2c_master {
|
|
||||||
($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => {
|
|
||||||
$(
|
|
||||||
impl<ADDR> I2cMaster<$I2CX, ADDR> {
|
|
||||||
pub fn $i2cx(
|
|
||||||
i2c: $I2CX,
|
|
||||||
cfg: MasterConfig,
|
|
||||||
sys_clk: impl Into<Hertz> + Copy,
|
|
||||||
speed_mode: I2cSpeed,
|
|
||||||
sys_cfg: Option<&mut pac::Sysconfig>,
|
|
||||||
) -> Self {
|
|
||||||
I2cMaster {
|
|
||||||
i2c_base: I2cBase::$i2cx(
|
|
||||||
i2c,
|
|
||||||
sys_clk,
|
|
||||||
speed_mode,
|
|
||||||
Some(&cfg),
|
|
||||||
None,
|
|
||||||
sys_cfg
|
|
||||||
),
|
|
||||||
_addr: PhantomData,
|
|
||||||
}
|
|
||||||
.enable_master()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn cancel_transfer(&self) {
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.cmd()
|
|
||||||
.write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) });
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_tx_fifo(&self) {
|
|
||||||
self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn clear_rx_fifo(&self) {
|
|
||||||
self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn enable_master(self) -> Self {
|
|
||||||
self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn disable_master(self) -> Self {
|
|
||||||
self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().clear_bit());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn load_fifo(&self, word: u8) {
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.data()
|
|
||||||
.write(|w| unsafe { w.bits(word as u32) });
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn read_fifo(&self) -> u8 {
|
|
||||||
self.i2c_base.i2c.data().read().bits() as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_handler_write(&mut self, init_cmd: &I2cCmd) {
|
|
||||||
self.clear_tx_fifo();
|
|
||||||
if *init_cmd == I2cCmd::Start {
|
|
||||||
self.i2c_base.stop_cmd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_base(
|
|
||||||
&mut self,
|
|
||||||
addr: I2cAddress,
|
|
||||||
init_cmd: I2cCmd,
|
|
||||||
bytes: impl IntoIterator<Item = u8>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let mut iter = bytes.into_iter();
|
|
||||||
// Load address
|
|
||||||
let (addr, addr_mode_bit) = I2cBase::<$I2CX>::unwrap_addr(addr);
|
|
||||||
self.i2c_base.i2c.address().write(|w| unsafe {
|
|
||||||
w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit)
|
|
||||||
});
|
|
||||||
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.cmd()
|
|
||||||
.write(|w| unsafe { w.bits(init_cmd as u32) });
|
|
||||||
let mut load_if_next_available = || {
|
|
||||||
if let Some(next_byte) = iter.next() {
|
|
||||||
self.load_fifo(next_byte);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
loop {
|
|
||||||
let status_reader = self.i2c_base.i2c.status().read();
|
|
||||||
if status_reader.arblost().bit_is_set() {
|
|
||||||
self.error_handler_write(&init_cmd);
|
|
||||||
return Err(Error::ArbitrationLost);
|
|
||||||
} else if status_reader.nackaddr().bit_is_set() {
|
|
||||||
self.error_handler_write(&init_cmd);
|
|
||||||
return Err(Error::NackAddr);
|
|
||||||
} else if status_reader.nackdata().bit_is_set() {
|
|
||||||
self.error_handler_write(&init_cmd);
|
|
||||||
return Err(Error::NackData);
|
|
||||||
} else if status_reader.idle().bit_is_set() {
|
|
||||||
return Ok(());
|
|
||||||
} else {
|
|
||||||
while !status_reader.txnfull().bit_is_set() {
|
|
||||||
load_if_next_available();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_from_buffer(
|
|
||||||
&mut self,
|
|
||||||
init_cmd: I2cCmd,
|
|
||||||
addr: I2cAddress,
|
|
||||||
output: &[u8],
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let len = output.len();
|
|
||||||
// It should theoretically possible to transfer larger data sizes by tracking
|
|
||||||
// the number of sent words and setting it to 0x7fe as soon as only that many
|
|
||||||
// bytes are remaining. However, large transfer like this are not common. This
|
|
||||||
// feature will therefore not be supported for now.
|
|
||||||
if len > 0x7fe {
|
|
||||||
return Err(Error::DataTooLarge);
|
|
||||||
}
|
|
||||||
// Load number of words
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.words()
|
|
||||||
.write(|w| unsafe { w.bits(len as u32) });
|
|
||||||
let mut bytes = output.iter();
|
|
||||||
// FIFO has a depth of 16. We load slightly above the trigger level
|
|
||||||
// but not all of it because the transaction might fail immediately
|
|
||||||
const FILL_DEPTH: usize = 12;
|
|
||||||
|
|
||||||
// load the FIFO
|
|
||||||
for _ in 0..core::cmp::min(FILL_DEPTH, len) {
|
|
||||||
self.load_fifo(*bytes.next().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.write_base(addr, init_cmd, output.iter().cloned())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> {
|
|
||||||
let len = buffer.len();
|
|
||||||
// It should theoretically possible to transfer larger data sizes by tracking
|
|
||||||
// the number of sent words and setting it to 0x7fe as soon as only that many
|
|
||||||
// bytes are remaining. However, large transfer like this are not common. This
|
|
||||||
// feature will therefore not be supported for now.
|
|
||||||
if len > 0x7fe {
|
|
||||||
return Err(Error::DataTooLarge);
|
|
||||||
}
|
|
||||||
// Clear the receive FIFO
|
|
||||||
self.clear_rx_fifo();
|
|
||||||
|
|
||||||
// Load number of words
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.words()
|
|
||||||
.write(|w| unsafe { w.bits(len as u32) });
|
|
||||||
let (addr, addr_mode_bit) = match addr {
|
|
||||||
I2cAddress::Regular(addr) => (addr as u16, 0 << 15),
|
|
||||||
I2cAddress::TenBit(addr) => (addr, 1 << 15),
|
|
||||||
};
|
|
||||||
// Load address
|
|
||||||
self.i2c_base.i2c.address().write(|w| unsafe {
|
|
||||||
w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut buf_iter = buffer.iter_mut();
|
|
||||||
let mut read_bytes = 0;
|
|
||||||
// Start receive transfer
|
|
||||||
self.i2c_base
|
|
||||||
.i2c
|
|
||||||
.cmd()
|
|
||||||
.write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) });
|
|
||||||
let mut read_if_next_available = || {
|
|
||||||
if let Some(next_byte) = buf_iter.next() {
|
|
||||||
*next_byte = self.read_fifo();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
loop {
|
|
||||||
let status_reader = self.i2c_base.i2c.status().read();
|
|
||||||
if status_reader.arblost().bit_is_set() {
|
|
||||||
self.clear_rx_fifo();
|
|
||||||
return Err(Error::ArbitrationLost);
|
|
||||||
} else if status_reader.nackaddr().bit_is_set() {
|
|
||||||
self.clear_rx_fifo();
|
|
||||||
return Err(Error::NackAddr);
|
|
||||||
} else if status_reader.idle().bit_is_set() {
|
|
||||||
if read_bytes != len {
|
|
||||||
return Err(Error::InsufficientDataReceived);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
} else if status_reader.rxnempty().bit_is_set() {
|
|
||||||
read_if_next_available();
|
|
||||||
read_bytes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================================
|
|
||||||
// Embedded HAL I2C implementations
|
|
||||||
//======================================================================================
|
|
||||||
|
|
||||||
impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, SevenBitAddress> {
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
impl embedded_hal::i2c::I2c for I2cMaster<$I2CX, SevenBitAddress> {
|
|
||||||
fn transaction(
|
|
||||||
&mut self,
|
|
||||||
address: SevenBitAddress,
|
|
||||||
operations: &mut [Operation<'_>],
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
for operation in operations {
|
|
||||||
match operation {
|
|
||||||
Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?,
|
|
||||||
Operation::Write(buf) => self.write_from_buffer(
|
|
||||||
I2cCmd::StartWithStop,
|
|
||||||
I2cAddress::Regular(address),
|
|
||||||
buf,
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_hal::i2c::ErrorType for I2cMaster<$I2CX, TenBitAddress> {
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
impl embedded_hal::i2c::I2c<TenBitAddress> for I2cMaster<$I2CX, TenBitAddress> {
|
|
||||||
fn transaction(
|
|
||||||
&mut self,
|
|
||||||
address: TenBitAddress,
|
|
||||||
operations: &mut [Operation<'_>],
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
for operation in operations {
|
|
||||||
match operation {
|
|
||||||
Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?,
|
|
||||||
Operation::Write(buf) => self.write_from_buffer(
|
|
||||||
I2cCmd::StartWithStop,
|
|
||||||
I2cAddress::TenBit(address),
|
|
||||||
buf,
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i2c_master!(
|
|
||||||
pac::I2ca: (i2ca, PeripheralClocks::I2c0),
|
|
||||||
pac::I2cb: (i2cb, PeripheralClocks::I2c1),
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
//======================================================================================
|
//======================================================================================
|
||||||
// Embedded HAL I2C implementations
|
// Embedded HAL I2C implementations
|
||||||
//======================================================================================
|
//======================================================================================
|
||||||
|
@ -31,7 +31,7 @@ pub enum PortSel {
|
|||||||
PortB,
|
PortB,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum PeripheralSelect {
|
pub enum PeripheralSelect {
|
||||||
PortA = 0,
|
PortA = 0,
|
||||||
@ -54,6 +54,7 @@ pub enum PeripheralSelect {
|
|||||||
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
|
/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
|
||||||
/// perform those steps themselves.
|
/// perform those steps themselves.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct InterruptConfig {
|
pub struct InterruptConfig {
|
||||||
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
|
/// Interrupt target vector. Should always be set, might be required for disabling IRQs
|
||||||
pub id: pac::Interrupt,
|
pub id: pac::Interrupt,
|
||||||
|
@ -33,6 +33,7 @@ use embedded_hal::spi::{Mode, MODE_0};
|
|||||||
const FILL_DEPTH: usize = 12;
|
const FILL_DEPTH: usize = 12;
|
||||||
|
|
||||||
pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
|
pub const BMSTART_BMSTOP_MASK: u32 = 1 << 31;
|
||||||
|
pub const BMSKIPDATA_MASK: u32 = 1 << 30;
|
||||||
|
|
||||||
pub const DEFAULT_CLK_DIV: u16 = 2;
|
pub const DEFAULT_CLK_DIV: u16 = 2;
|
||||||
|
|
||||||
@ -288,6 +289,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,
|
||||||
@ -296,6 +298,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>,
|
||||||
@ -383,6 +386,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
|
||||||
@ -532,6 +537,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,6 +581,7 @@ impl SpiClkConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum SpiClkConfigError {
|
pub enum SpiClkConfigError {
|
||||||
#[error("division by zero")]
|
#[error("division by zero")]
|
||||||
DivIsZero,
|
DivIsZero,
|
||||||
|
@ -30,7 +30,7 @@ For full details on the autgenerated API, please see the
|
|||||||
|
|
||||||
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for `defmt` by adding the
|
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for `defmt` by adding the
|
||||||
[`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
|
[`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
|
||||||
- [`debug`]: Add `Debug` derives for various structures
|
- `debug`: Add `Debug` derives for various structures
|
||||||
|
|
||||||
## Regenerating the PAC
|
## Regenerating the PAC
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user