ETM improvements (#2427)
* ETM simplifications * Work with GPIO signals * Fix changelog
This commit is contained in:
parent
665fb0e278
commit
eabb6fb1c6
@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `gpio::Output::peripheral_input()` (#2418)
|
||||
- `{Uart, UartRx, UartTx}::apply_config()` (#2449)
|
||||
- `{Uart, UartRx, UartTx}` now implement `embassy_embedded_hal::SetConfig` (#2449)
|
||||
- GPIO ETM tasks and events now accept `InputSignal` and `OutputSignal` (#2427)
|
||||
|
||||
### Changed
|
||||
|
||||
@ -78,6 +79,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430)
|
||||
- The `configure_for_async` DMA functions have been removed (#2430)
|
||||
- The `Uart::{change_baud, change_stop_bits}` functions have been removed (#2449)
|
||||
- `gpio::{Input, Output, OutputOpenDrain, Flex, GpioPin}::{peripheral_input, into_peripheral_output}` have been removed. (#2418)
|
||||
- The `GpioEtm` prefix has been removed from `gpio::etm` types (#2427)
|
||||
- The `TimerEtm` prefix has been removed from `timer::timg::etm` types (#2427)
|
||||
- The `SysTimerEtm` prefix has been removed from `timer::systimer::etm` types (#2427)
|
||||
- The `GpioEtmEventRising`, `GpioEtmEventFalling`, `GpioEtmEventAny` types have been replaced with `Event` (#2427)
|
||||
- The `TaskSet`, `TaskClear`, `TaskToggle` types have been replaced with `Task` (#2427)
|
||||
|
||||
## [0.21.1]
|
||||
|
||||
|
||||
@ -231,6 +231,14 @@ The previous signal function have been replaced by `split`. This change affects
|
||||
`into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to
|
||||
the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead.
|
||||
|
||||
## ETM changes
|
||||
|
||||
- The types are no longer prefixed with `GpioEtm`, `TimerEtm` or `SysTimerEtm`. You can still use
|
||||
import aliasses in case you need to differentiate due to name collisions
|
||||
(e.g. `use esp_hal::gpio::etm::Event as GpioEtmEvent`).
|
||||
- The old task and event types have been replaced by `Task` and `Event`.
|
||||
- GPIO tasks and events are no longer generic.
|
||||
|
||||
## Changes to peripheral configuration
|
||||
|
||||
### The `uart::config` module has been removed
|
||||
@ -243,4 +251,4 @@ The module's contents have been moved into `uart`.
|
||||
```
|
||||
|
||||
If you work with multiple configurable peripherals, you may want to import the `uart` module and
|
||||
refer to the `Config` struct as `uart::Config`.
|
||||
refer to the `Config` struct as `uart::Config`.
|
||||
@ -24,10 +24,8 @@
|
||||
//! ```rust, no_run
|
||||
#![doc = crate::before_snippet!()]
|
||||
//! # use esp_hal::gpio::Io;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmChannels;
|
||||
//! # use esp_hal::gpio::etm::{Channels, InputConfig, OutputConfig};
|
||||
//! # use esp_hal::etm::Etm;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmInputConfig;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmOutputConfig;
|
||||
//! # use esp_hal::gpio::Pull;
|
||||
//! # use esp_hal::gpio::Level;
|
||||
//!
|
||||
@ -36,18 +34,18 @@
|
||||
//! let button = io.pins.gpio9;
|
||||
//!
|
||||
//! // setup ETM
|
||||
//! let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
|
||||
//! let gpio_ext = Channels::new(peripherals.GPIO_SD);
|
||||
//! let led_task = gpio_ext.channel0_task.toggle(
|
||||
//! &mut led,
|
||||
//! GpioEtmOutputConfig {
|
||||
//! open_drain: false,
|
||||
//! pull: Pull::None,
|
||||
//! initial_state: Level::Low,
|
||||
//! },
|
||||
//! &mut led,
|
||||
//! OutputConfig {
|
||||
//! open_drain: false,
|
||||
//! pull: Pull::None,
|
||||
//! initial_state: Level::Low,
|
||||
//! },
|
||||
//! );
|
||||
//! let button_event = gpio_ext
|
||||
//! .channel0_event
|
||||
//! .falling_edge(button, GpioEtmInputConfig { pull: Pull::Down });
|
||||
//! .falling_edge(button, InputConfig { pull: Pull::Down });
|
||||
//!
|
||||
//! let etm = Etm::new(peripherals.SOC_ETM);
|
||||
//! let channel0 = etm.channel0;
|
||||
|
||||
@ -26,21 +26,21 @@
|
||||
//! ```rust, no_run
|
||||
#![doc = crate::before_snippet!()]
|
||||
//! # use esp_hal::gpio::Io;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmChannels;
|
||||
//! # use esp_hal::gpio::etm::Channels;
|
||||
//! # use esp_hal::etm::Etm;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmInputConfig;
|
||||
//! # use esp_hal::gpio::etm::GpioEtmOutputConfig;
|
||||
//! # use esp_hal::gpio::etm::InputConfig;
|
||||
//! # use esp_hal::gpio::etm::OutputConfig;
|
||||
//! # use esp_hal::gpio::Pull;
|
||||
//! # use esp_hal::gpio::Level;
|
||||
//!
|
||||
//! #
|
||||
//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
//! # let mut led = io.pins.gpio1;
|
||||
//! # let button = io.pins.gpio9;
|
||||
//!
|
||||
//! let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
|
||||
//! let gpio_ext = Channels::new(peripherals.GPIO_SD);
|
||||
//! let led_task = gpio_ext.channel0_task.toggle(
|
||||
//! &mut led,
|
||||
//! GpioEtmOutputConfig {
|
||||
//! OutputConfig {
|
||||
//! open_drain: false,
|
||||
//! pull: Pull::None,
|
||||
//! initial_state: Level::Low,
|
||||
@ -48,77 +48,84 @@
|
||||
//! );
|
||||
//! let button_event = gpio_ext
|
||||
//! .channel0_event
|
||||
//! .falling_edge(button, GpioEtmInputConfig { pull: Pull::Down });
|
||||
//! .falling_edge(button, InputConfig { pull: Pull::Down });
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
gpio::{Level, Pull},
|
||||
gpio::{
|
||||
interconnect::{InputSignal, OutputSignal},
|
||||
Level,
|
||||
Pull,
|
||||
},
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::GPIO_SD,
|
||||
private,
|
||||
};
|
||||
|
||||
/// All the GPIO ETM channels
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmChannels<'d> {
|
||||
_gpio_sd: PeripheralRef<'d, crate::peripherals::GPIO_SD>,
|
||||
pub struct Channels<'d> {
|
||||
_gpio_sd: PeripheralRef<'d, GPIO_SD>,
|
||||
/// Task channel 0 for triggering GPIO tasks.
|
||||
pub channel0_task: GpioEtmTaskChannel<0>,
|
||||
pub channel0_task: TaskChannel<0>,
|
||||
/// Event channel 0 for handling GPIO events.
|
||||
pub channel0_event: GpioEtmEventChannel<0>,
|
||||
pub channel0_event: EventChannel<0>,
|
||||
/// Task channel 1 for triggering GPIO tasks.
|
||||
pub channel1_task: GpioEtmTaskChannel<1>,
|
||||
pub channel1_task: TaskChannel<1>,
|
||||
/// Event channel 1 for handling GPIO events.
|
||||
pub channel1_event: GpioEtmEventChannel<1>,
|
||||
pub channel1_event: EventChannel<1>,
|
||||
/// Task channel 2 for triggering GPIO tasks.
|
||||
pub channel2_task: GpioEtmTaskChannel<2>,
|
||||
pub channel2_task: TaskChannel<2>,
|
||||
/// Event channel 2 for handling GPIO events.
|
||||
pub channel2_event: GpioEtmEventChannel<2>,
|
||||
pub channel2_event: EventChannel<2>,
|
||||
/// Task channel 3 for triggering GPIO tasks.
|
||||
pub channel3_task: GpioEtmTaskChannel<3>,
|
||||
pub channel3_task: TaskChannel<3>,
|
||||
/// Event channel 3 for handling GPIO events.
|
||||
pub channel3_event: GpioEtmEventChannel<3>,
|
||||
pub channel3_event: EventChannel<3>,
|
||||
/// Task channel 4 for triggering GPIO tasks.
|
||||
pub channel4_task: GpioEtmTaskChannel<4>,
|
||||
pub channel4_task: TaskChannel<4>,
|
||||
/// Event channel 4 for handling GPIO events.
|
||||
pub channel4_event: GpioEtmEventChannel<4>,
|
||||
pub channel4_event: EventChannel<4>,
|
||||
/// Task channel 5 for triggering GPIO tasks.
|
||||
pub channel5_task: GpioEtmTaskChannel<5>,
|
||||
pub channel5_task: TaskChannel<5>,
|
||||
/// Event channel 5 for handling GPIO events.
|
||||
pub channel5_event: GpioEtmEventChannel<5>,
|
||||
pub channel5_event: EventChannel<5>,
|
||||
/// Task channel 6 for triggering GPIO tasks.
|
||||
pub channel6_task: GpioEtmTaskChannel<6>,
|
||||
pub channel6_task: TaskChannel<6>,
|
||||
/// Event channel 6 for handling GPIO events.
|
||||
pub channel6_event: GpioEtmEventChannel<6>,
|
||||
pub channel6_event: EventChannel<6>,
|
||||
/// Task channel 7 for triggering GPIO tasks.
|
||||
pub channel7_task: GpioEtmTaskChannel<7>,
|
||||
pub channel7_task: TaskChannel<7>,
|
||||
/// Event channel 7 for handling GPIO events.
|
||||
pub channel7_event: GpioEtmEventChannel<7>,
|
||||
pub channel7_event: EventChannel<7>,
|
||||
}
|
||||
|
||||
impl<'d> GpioEtmChannels<'d> {
|
||||
impl<'d> Channels<'d> {
|
||||
/// Create a new instance
|
||||
pub fn new(peripheral: impl Peripheral<P = crate::peripherals::GPIO_SD> + 'd) -> Self {
|
||||
pub fn new(peripheral: impl Peripheral<P = GPIO_SD> + 'd) -> Self {
|
||||
crate::into_ref!(peripheral);
|
||||
|
||||
Self {
|
||||
_gpio_sd: peripheral,
|
||||
channel0_task: GpioEtmTaskChannel {},
|
||||
channel0_event: GpioEtmEventChannel {},
|
||||
channel1_task: GpioEtmTaskChannel {},
|
||||
channel1_event: GpioEtmEventChannel {},
|
||||
channel2_task: GpioEtmTaskChannel {},
|
||||
channel2_event: GpioEtmEventChannel {},
|
||||
channel3_task: GpioEtmTaskChannel {},
|
||||
channel3_event: GpioEtmEventChannel {},
|
||||
channel4_task: GpioEtmTaskChannel {},
|
||||
channel4_event: GpioEtmEventChannel {},
|
||||
channel5_task: GpioEtmTaskChannel {},
|
||||
channel5_event: GpioEtmEventChannel {},
|
||||
channel6_task: GpioEtmTaskChannel {},
|
||||
channel6_event: GpioEtmEventChannel {},
|
||||
channel7_task: GpioEtmTaskChannel {},
|
||||
channel7_event: GpioEtmEventChannel {},
|
||||
channel0_task: TaskChannel {},
|
||||
channel0_event: EventChannel {},
|
||||
channel1_task: TaskChannel {},
|
||||
channel1_event: EventChannel {},
|
||||
channel2_task: TaskChannel {},
|
||||
channel2_event: EventChannel {},
|
||||
channel3_task: TaskChannel {},
|
||||
channel3_event: EventChannel {},
|
||||
channel4_task: TaskChannel {},
|
||||
channel4_event: EventChannel {},
|
||||
channel5_task: TaskChannel {},
|
||||
channel5_event: EventChannel {},
|
||||
channel6_task: TaskChannel {},
|
||||
channel6_event: EventChannel {},
|
||||
channel7_task: TaskChannel {},
|
||||
channel7_event: EventChannel {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,143 +133,102 @@ impl<'d> GpioEtmChannels<'d> {
|
||||
/// Configuration for an ETM controlled GPIO input pin
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct GpioEtmInputConfig {
|
||||
pub struct InputConfig {
|
||||
/// Configuration for the internal pull-up resistors
|
||||
pub pull: Pull,
|
||||
}
|
||||
|
||||
impl Default for GpioEtmInputConfig {
|
||||
impl Default for InputConfig {
|
||||
fn default() -> Self {
|
||||
Self { pull: Pull::None }
|
||||
}
|
||||
}
|
||||
|
||||
/// An ETM controlled GPIO event
|
||||
pub struct GpioEtmEventChannel<const C: u8> {}
|
||||
pub struct EventChannel<const C: u8> {}
|
||||
|
||||
impl<const C: u8> GpioEtmEventChannel<C> {
|
||||
impl<const C: u8> EventChannel<C> {
|
||||
/// Trigger at rising edge
|
||||
pub fn rising_edge<'d, PIN>(
|
||||
pub fn rising_edge<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmInputConfig,
|
||||
) -> GpioEtmEventChannelRising<'d, PIN, C>
|
||||
where
|
||||
PIN: super::InputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
|
||||
pin.init_input(pin_config.pull, private::Internal);
|
||||
|
||||
enable_event_channel(C, pin.number());
|
||||
GpioEtmEventChannelRising { _pin: pin }
|
||||
pin: impl Peripheral<P = impl Into<InputSignal>> + 'd,
|
||||
pin_config: InputConfig,
|
||||
) -> Event<'d> {
|
||||
self.into_event(pin, pin_config, EventKind::Rising)
|
||||
}
|
||||
|
||||
/// Trigger at falling edge
|
||||
pub fn falling_edge<'d, PIN>(
|
||||
pub fn falling_edge<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmInputConfig,
|
||||
) -> GpioEtmEventChannelFalling<'d, PIN, C>
|
||||
where
|
||||
PIN: super::InputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
|
||||
pin.init_input(pin_config.pull, private::Internal);
|
||||
|
||||
enable_event_channel(C, pin.number());
|
||||
GpioEtmEventChannelFalling { _pin: pin }
|
||||
pin: impl Peripheral<P = impl Into<InputSignal>> + 'd,
|
||||
pin_config: InputConfig,
|
||||
) -> Event<'d> {
|
||||
self.into_event(pin, pin_config, EventKind::Falling)
|
||||
}
|
||||
|
||||
/// Trigger at any edge
|
||||
pub fn any_edge<'d, PIN>(
|
||||
pub fn any_edge<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmInputConfig,
|
||||
) -> GpioEtmEventChannelAny<'d, PIN, C>
|
||||
where
|
||||
PIN: super::InputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
pin: impl Peripheral<P = impl Into<InputSignal>> + 'd,
|
||||
pin_config: InputConfig,
|
||||
) -> Event<'d> {
|
||||
self.into_event(pin, pin_config, EventKind::Any)
|
||||
}
|
||||
|
||||
fn into_event<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = impl Into<InputSignal>> + 'd,
|
||||
pin_config: InputConfig,
|
||||
kind: EventKind,
|
||||
) -> Event<'d> {
|
||||
crate::into_mapped_ref!(pin);
|
||||
|
||||
pin.init_input(pin_config.pull, private::Internal);
|
||||
|
||||
enable_event_channel(C, pin.number());
|
||||
GpioEtmEventChannelAny { _pin: pin }
|
||||
Event {
|
||||
id: kind.id() + C,
|
||||
_pin: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum EventKind {
|
||||
Rising,
|
||||
Falling,
|
||||
Any,
|
||||
}
|
||||
|
||||
impl EventKind {
|
||||
fn id(&self) -> u8 {
|
||||
match self {
|
||||
EventKind::Rising => 1,
|
||||
EventKind::Falling => 9,
|
||||
EventKind::Any => 17,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Event for rising edge
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmEventChannelRising<'d, PIN, const C: u8>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
pub struct Event<'d> {
|
||||
_pin: PhantomData<&'d mut ()>,
|
||||
id: u8,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmEventChannelRising<'_, PIN, C> where
|
||||
PIN: super::Pin
|
||||
{
|
||||
}
|
||||
impl private::Sealed for Event<'_> {}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelRising<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
impl crate::etm::EtmEvent for Event<'_> {
|
||||
fn id(&self) -> u8 {
|
||||
1 + C
|
||||
}
|
||||
}
|
||||
|
||||
/// Event for falling edge
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmEventChannelFalling<'d, PIN, const C: u8>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmEventChannelFalling<'_, PIN, C> where
|
||||
PIN: super::Pin
|
||||
{
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelFalling<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
fn id(&self) -> u8 {
|
||||
9 + C
|
||||
}
|
||||
}
|
||||
|
||||
/// Event for any edge
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmEventChannelAny<'d, PIN, const C: u8>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmEventChannelAny<'_, PIN, C> where PIN: super::Pin {}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelAny<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
fn id(&self) -> u8 {
|
||||
17 + C
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for an ETM controlled GPIO output pin
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct GpioEtmOutputConfig {
|
||||
pub struct OutputConfig {
|
||||
/// Set to open-drain output
|
||||
pub open_drain: bool,
|
||||
/// Only used when open-drain
|
||||
@ -271,7 +237,7 @@ pub struct GpioEtmOutputConfig {
|
||||
pub initial_state: Level,
|
||||
}
|
||||
|
||||
impl Default for GpioEtmOutputConfig {
|
||||
impl Default for OutputConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
open_drain: false,
|
||||
@ -282,70 +248,48 @@ impl Default for GpioEtmOutputConfig {
|
||||
}
|
||||
|
||||
/// An ETM controlled GPIO task
|
||||
pub struct GpioEtmTaskChannel<const C: u8> {}
|
||||
pub struct TaskChannel<const C: u8> {}
|
||||
|
||||
impl<const C: u8> GpioEtmTaskChannel<C> {
|
||||
impl<const C: u8> TaskChannel<C> {
|
||||
// In theory we could have multiple pins assigned to the same task. Not sure how
|
||||
// useful that would be. If we want to support it, the easiest would be
|
||||
// to offer additional functions like `set2`, `set3` etc. where the
|
||||
// number is the pin-count
|
||||
|
||||
/// Task to set a high level
|
||||
pub fn set<'d, PIN>(
|
||||
pub fn set<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmOutputConfig,
|
||||
) -> GpioEtmTaskSet<'d, PIN, C>
|
||||
where
|
||||
PIN: super::OutputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
|
||||
pin.set_output_high(pin_config.initial_state.into(), private::Internal);
|
||||
if pin_config.open_drain {
|
||||
pin.pull_direction(pin_config.pull, private::Internal);
|
||||
pin.set_to_open_drain_output(private::Internal);
|
||||
} else {
|
||||
pin.set_to_push_pull_output(private::Internal);
|
||||
}
|
||||
|
||||
enable_task_channel(C, pin.number());
|
||||
GpioEtmTaskSet { _pin: pin }
|
||||
pin: impl Peripheral<P = impl Into<OutputSignal>> + 'd,
|
||||
pin_config: OutputConfig,
|
||||
) -> Task<'d> {
|
||||
self.into_task(pin, pin_config, TaskKind::Set)
|
||||
}
|
||||
|
||||
/// Task to set a low level
|
||||
pub fn clear<'d, PIN>(
|
||||
pub fn clear<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmOutputConfig,
|
||||
) -> GpioEtmTaskClear<'d, PIN, C>
|
||||
where
|
||||
PIN: super::OutputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
|
||||
pin.set_output_high(pin_config.initial_state.into(), private::Internal);
|
||||
if pin_config.open_drain {
|
||||
pin.pull_direction(pin_config.pull, private::Internal);
|
||||
pin.set_to_open_drain_output(private::Internal);
|
||||
} else {
|
||||
pin.set_to_push_pull_output(private::Internal);
|
||||
}
|
||||
|
||||
enable_task_channel(C, pin.number());
|
||||
GpioEtmTaskClear { _pin: pin }
|
||||
pin: impl Peripheral<P = impl Into<OutputSignal>> + 'd,
|
||||
pin_config: OutputConfig,
|
||||
) -> Task<'d> {
|
||||
self.into_task(pin, pin_config, TaskKind::Clear)
|
||||
}
|
||||
|
||||
/// Task to toggle the level
|
||||
pub fn toggle<'d, PIN>(
|
||||
pub fn toggle<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = PIN> + 'd,
|
||||
pin_config: GpioEtmOutputConfig,
|
||||
) -> GpioEtmTaskToggle<'d, PIN, C>
|
||||
where
|
||||
PIN: super::OutputPin,
|
||||
{
|
||||
crate::into_ref!(pin);
|
||||
pin: impl Peripheral<P = impl Into<OutputSignal>> + 'd,
|
||||
pin_config: OutputConfig,
|
||||
) -> Task<'d> {
|
||||
self.into_task(pin, pin_config, TaskKind::Toggle)
|
||||
}
|
||||
|
||||
fn into_task<'d>(
|
||||
self,
|
||||
pin: impl Peripheral<P = impl Into<OutputSignal>> + 'd,
|
||||
pin_config: OutputConfig,
|
||||
kind: TaskKind,
|
||||
) -> Task<'d> {
|
||||
crate::into_mapped_ref!(pin);
|
||||
|
||||
pin.set_output_high(pin_config.initial_state.into(), private::Internal);
|
||||
if pin_config.open_drain {
|
||||
@ -356,66 +300,47 @@ impl<const C: u8> GpioEtmTaskChannel<C> {
|
||||
}
|
||||
|
||||
enable_task_channel(C, pin.number());
|
||||
GpioEtmTaskToggle { _pin: pin }
|
||||
Task {
|
||||
id: kind.id() + C,
|
||||
_pin: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum TaskKind {
|
||||
Set,
|
||||
Clear,
|
||||
Toggle,
|
||||
}
|
||||
|
||||
impl TaskKind {
|
||||
fn id(&self) -> u8 {
|
||||
match self {
|
||||
TaskKind::Set => 1,
|
||||
TaskKind::Clear => 9,
|
||||
TaskKind::Toggle => 17,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Task for set operation
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmTaskSet<'d, PIN, const C: u8>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
pub struct Task<'d> {
|
||||
_pin: PhantomData<&'d mut ()>,
|
||||
id: u8,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmTaskSet<'_, PIN, C> where PIN: super::Pin {}
|
||||
impl private::Sealed for Task<'_> {}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskSet<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
impl crate::etm::EtmTask for Task<'_> {
|
||||
fn id(&self) -> u8 {
|
||||
1 + C
|
||||
}
|
||||
}
|
||||
|
||||
/// Task for clear operation
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmTaskClear<'d, PIN, const C: u8> {
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmTaskClear<'_, PIN, C> where PIN: super::Pin {}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskClear<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
fn id(&self) -> u8 {
|
||||
9 + C
|
||||
}
|
||||
}
|
||||
|
||||
/// Task for toggle operation
|
||||
#[non_exhaustive]
|
||||
pub struct GpioEtmTaskToggle<'d, PIN, const C: u8> {
|
||||
_pin: PeripheralRef<'d, PIN>,
|
||||
}
|
||||
|
||||
impl<PIN, const C: u8> private::Sealed for GpioEtmTaskToggle<'_, PIN, C> where PIN: super::Pin {}
|
||||
|
||||
impl<PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskToggle<'_, PIN, C>
|
||||
where
|
||||
PIN: super::Pin,
|
||||
{
|
||||
fn id(&self) -> u8 {
|
||||
17 + C
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_task_channel(channel: u8, pin: u8) {
|
||||
let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() };
|
||||
let gpio_sd = unsafe { GPIO_SD::steal() };
|
||||
let ptr = unsafe { gpio_sd.etm_task_p0_cfg().as_ptr().add(pin as usize / 4) };
|
||||
let shift = 8 * (pin as usize % 4);
|
||||
// bit 0 = en, bit 1-3 = channel
|
||||
@ -427,7 +352,7 @@ fn enable_task_channel(channel: u8, pin: u8) {
|
||||
}
|
||||
|
||||
fn enable_event_channel(channel: u8, pin: u8) {
|
||||
let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() };
|
||||
let gpio_sd = unsafe { GPIO_SD::steal() };
|
||||
gpio_sd
|
||||
.etm_event_ch_cfg(channel as usize)
|
||||
.modify(|_, w| w.event_en().clear_bit());
|
||||
|
||||
@ -60,6 +60,15 @@ pub struct InputSignal {
|
||||
is_inverted: bool,
|
||||
}
|
||||
|
||||
impl<P> From<P> for InputSignal
|
||||
where
|
||||
P: InputPin,
|
||||
{
|
||||
fn from(input: P) -> Self {
|
||||
Self::new(input.degrade())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for InputSignal {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@ -87,6 +96,11 @@ impl InputSignal {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the GPIO number of the underlying pin.
|
||||
pub fn number(&self) -> u8 {
|
||||
self.pin.number()
|
||||
}
|
||||
|
||||
/// Returns the current signal level.
|
||||
pub fn get_level(&self) -> Level {
|
||||
self.is_input_high(private::Internal).into()
|
||||
@ -120,9 +134,7 @@ impl InputSignal {
|
||||
w.in_sel().bits(input)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl InputSignal {
|
||||
/// Connect the pin to a peripheral input signal.
|
||||
///
|
||||
/// Since there can only be one input signal connected to a peripheral at a
|
||||
@ -191,6 +203,15 @@ pub struct OutputSignal {
|
||||
is_inverted: bool,
|
||||
}
|
||||
|
||||
impl<P> From<P> for OutputSignal
|
||||
where
|
||||
P: OutputPin,
|
||||
{
|
||||
fn from(input: P) -> Self {
|
||||
Self::new(input.degrade())
|
||||
}
|
||||
}
|
||||
|
||||
impl Peripheral for OutputSignal {
|
||||
type P = Self;
|
||||
|
||||
@ -212,6 +233,11 @@ impl OutputSignal {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the GPIO number of the underlying pin.
|
||||
pub fn number(&self) -> u8 {
|
||||
self.pin.number()
|
||||
}
|
||||
|
||||
/// Inverts the peripheral's output signal.
|
||||
///
|
||||
/// Calling this function multiple times toggles the setting.
|
||||
@ -268,9 +294,7 @@ impl OutputSignal {
|
||||
w.oen_inv_sel().bit(invert_enable)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputSignal {
|
||||
/// Connect the pin to a peripheral input signal.
|
||||
///
|
||||
/// Since there can only be one signal connected to a peripheral input at a
|
||||
@ -434,9 +458,7 @@ where
|
||||
P: InputPin,
|
||||
{
|
||||
fn from(input: P) -> Self {
|
||||
Self(InputConnectionInner::Input(InputSignal::new(
|
||||
input.degrade(),
|
||||
)))
|
||||
Self(InputConnectionInner::Input(InputSignal::from(input)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -527,9 +549,7 @@ where
|
||||
P: OutputPin,
|
||||
{
|
||||
fn from(input: P) -> Self {
|
||||
Self(OutputConnectionInner::Output(OutputSignal::new(
|
||||
input.degrade(),
|
||||
)))
|
||||
Self(OutputConnectionInner::Output(OutputSignal::from(input)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1104,27 +1104,25 @@ pub mod etm {
|
||||
//! ## Example
|
||||
//! ```rust, no_run
|
||||
#![doc = crate::before_snippet!()]
|
||||
//! # use esp_hal::timer::systimer::{etm::SysTimerEtmEvent, SystemTimer};
|
||||
//! # use esp_hal::timer::systimer::{etm::Event, SystemTimer};
|
||||
//! # use fugit::ExtU32;
|
||||
//! let syst = SystemTimer::new(peripherals.SYSTIMER);
|
||||
//! let syst_alarms = syst.split();
|
||||
//! let mut alarm0 = syst_alarms.alarm0.into_periodic();
|
||||
//! alarm0.set_period(1u32.secs());
|
||||
//!
|
||||
//! let timer_event = SysTimerEtmEvent::new(&mut alarm0);
|
||||
//! let timer_event = Event::new(&mut alarm0);
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
use super::*;
|
||||
|
||||
/// An ETM controlled SYSTIMER event
|
||||
pub struct SysTimerEtmEvent<'a, 'd, M, DM: crate::Mode, COMP, UNIT> {
|
||||
pub struct Event<'a, 'd, M, DM: crate::Mode, COMP, UNIT> {
|
||||
alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>,
|
||||
}
|
||||
|
||||
impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit>
|
||||
SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT>
|
||||
{
|
||||
impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> Event<'a, 'd, M, DM, COMP, UNIT> {
|
||||
/// Creates an ETM event from the given [Alarm]
|
||||
pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>) -> Self {
|
||||
Self { alarm }
|
||||
@ -1138,12 +1136,12 @@ pub mod etm {
|
||||
}
|
||||
|
||||
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed
|
||||
for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT>
|
||||
for Event<'_, '_, M, DM, COMP, UNIT>
|
||||
{
|
||||
}
|
||||
|
||||
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent
|
||||
for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT>
|
||||
for Event<'_, '_, M, DM, COMP, UNIT>
|
||||
{
|
||||
fn id(&self) -> u8 {
|
||||
50 + self.alarm.comparator.channel()
|
||||
|
||||
@ -1349,87 +1349,87 @@ pub mod etm {
|
||||
use crate::etm::{EtmEvent, EtmTask};
|
||||
|
||||
/// Event Task Matrix event for a timer.
|
||||
pub struct TimerEtmEvent {
|
||||
pub struct Event {
|
||||
id: u8,
|
||||
}
|
||||
|
||||
/// Event Task Matrix task for a timer.
|
||||
pub struct TimerEtmTask {
|
||||
pub struct Task {
|
||||
id: u8,
|
||||
}
|
||||
|
||||
impl EtmEvent for TimerEtmEvent {
|
||||
impl EtmEvent for Event {
|
||||
fn id(&self) -> u8 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for TimerEtmEvent {}
|
||||
impl Sealed for Event {}
|
||||
|
||||
impl EtmTask for TimerEtmTask {
|
||||
impl EtmTask for Task {
|
||||
fn id(&self) -> u8 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for TimerEtmTask {}
|
||||
impl Sealed for Task {}
|
||||
|
||||
/// General purpose timer ETM events.
|
||||
pub trait TimerEtmEvents<TG> {
|
||||
pub trait Events<TG> {
|
||||
/// ETM event triggered on alarm
|
||||
fn on_alarm(&self) -> TimerEtmEvent;
|
||||
fn on_alarm(&self) -> Event;
|
||||
}
|
||||
|
||||
/// General purpose timer ETM tasks
|
||||
pub trait TimerEtmTasks<TG> {
|
||||
pub trait Tasks<TG> {
|
||||
/// ETM task to start the counter
|
||||
fn cnt_start(&self) -> TimerEtmTask;
|
||||
fn cnt_start(&self) -> Task;
|
||||
|
||||
/// ETM task to start the alarm
|
||||
fn cnt_stop(&self) -> TimerEtmTask;
|
||||
fn cnt_stop(&self) -> Task;
|
||||
|
||||
/// ETM task to stop the counter
|
||||
fn cnt_reload(&self) -> TimerEtmTask;
|
||||
fn cnt_reload(&self) -> Task;
|
||||
|
||||
/// ETM task to reload the counter
|
||||
fn cnt_cap(&self) -> TimerEtmTask;
|
||||
fn cnt_cap(&self) -> Task;
|
||||
|
||||
/// ETM task to load the counter with the value stored when the last
|
||||
/// `now()` was called
|
||||
fn alarm_start(&self) -> TimerEtmTask;
|
||||
fn alarm_start(&self) -> Task;
|
||||
}
|
||||
|
||||
impl<TG> TimerEtmEvents<TG> for Timer0<TG>
|
||||
impl<TG> Events<TG> for Timer0<TG>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
{
|
||||
fn on_alarm(&self) -> TimerEtmEvent {
|
||||
TimerEtmEvent { id: 48 + TG::id() }
|
||||
fn on_alarm(&self) -> Event {
|
||||
Event { id: 48 + TG::id() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<TG> TimerEtmTasks<TG> for Timer0<TG>
|
||||
impl<TG> Tasks<TG> for Timer0<TG>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
{
|
||||
fn cnt_start(&self) -> TimerEtmTask {
|
||||
TimerEtmTask { id: 88 + TG::id() }
|
||||
fn cnt_start(&self) -> Task {
|
||||
Task { id: 88 + TG::id() }
|
||||
}
|
||||
|
||||
fn alarm_start(&self) -> TimerEtmTask {
|
||||
TimerEtmTask { id: 90 + TG::id() }
|
||||
fn alarm_start(&self) -> Task {
|
||||
Task { id: 90 + TG::id() }
|
||||
}
|
||||
|
||||
fn cnt_stop(&self) -> TimerEtmTask {
|
||||
TimerEtmTask { id: 92 + TG::id() }
|
||||
fn cnt_stop(&self) -> Task {
|
||||
Task { id: 92 + TG::id() }
|
||||
}
|
||||
|
||||
fn cnt_reload(&self) -> TimerEtmTask {
|
||||
TimerEtmTask { id: 94 + TG::id() }
|
||||
fn cnt_reload(&self) -> Task {
|
||||
Task { id: 94 + TG::id() }
|
||||
}
|
||||
|
||||
fn cnt_cap(&self) -> TimerEtmTask {
|
||||
TimerEtmTask { id: 96 + TG::id() }
|
||||
fn cnt_cap(&self) -> Task {
|
||||
Task { id: 96 + TG::id() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,13 +12,13 @@ use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
etm::Etm,
|
||||
gpio::{
|
||||
etm::{GpioEtmChannels, GpioEtmOutputConfig},
|
||||
etm::{Channels, OutputConfig},
|
||||
Io,
|
||||
Level,
|
||||
Pull,
|
||||
},
|
||||
prelude::*,
|
||||
timer::systimer::{etm::SysTimerEtmEvent, Periodic, SystemTimer},
|
||||
timer::systimer::{etm::Event, Periodic, SystemTimer},
|
||||
};
|
||||
use fugit::ExtU32;
|
||||
|
||||
@ -35,17 +35,17 @@ fn main() -> ! {
|
||||
let mut led = io.pins.gpio1;
|
||||
|
||||
// setup ETM
|
||||
let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
|
||||
let gpio_ext = Channels::new(peripherals.GPIO_SD);
|
||||
let led_task = gpio_ext.channel0_task.toggle(
|
||||
&mut led,
|
||||
GpioEtmOutputConfig {
|
||||
OutputConfig {
|
||||
open_drain: false,
|
||||
pull: Pull::None,
|
||||
initial_state: Level::High,
|
||||
},
|
||||
);
|
||||
|
||||
let timer_event = SysTimerEtmEvent::new(&mut alarm0);
|
||||
let timer_event = Event::new(&mut alarm0);
|
||||
|
||||
let etm = Etm::new(peripherals.SOC_ETM);
|
||||
let channel0 = etm.channel0;
|
||||
|
||||
@ -12,7 +12,7 @@ use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
etm::Etm,
|
||||
gpio::{
|
||||
etm::{GpioEtmChannels, GpioEtmInputConfig, GpioEtmOutputConfig},
|
||||
etm::{Channels, InputConfig, OutputConfig},
|
||||
Io,
|
||||
Level,
|
||||
Output,
|
||||
@ -26,16 +26,17 @@ fn main() -> ! {
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
|
||||
let mut led = Output::new(io.pins.gpio1, Level::Low);
|
||||
let button = io.pins.gpio9;
|
||||
|
||||
led.set_high();
|
||||
|
||||
// setup ETM
|
||||
let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
|
||||
let gpio_ext = Channels::new(peripherals.GPIO_SD);
|
||||
let led_task = gpio_ext.channel0_task.toggle(
|
||||
&mut led,
|
||||
GpioEtmOutputConfig {
|
||||
led,
|
||||
OutputConfig {
|
||||
open_drain: false,
|
||||
pull: Pull::None,
|
||||
initial_state: Level::Low,
|
||||
@ -43,7 +44,7 @@ fn main() -> ! {
|
||||
);
|
||||
let button_event = gpio_ext
|
||||
.channel0_event
|
||||
.falling_edge(button, GpioEtmInputConfig { pull: Pull::Down });
|
||||
.falling_edge(button, InputConfig { pull: Pull::Down });
|
||||
|
||||
let etm = Etm::new(peripherals.SOC_ETM);
|
||||
let channel0 = etm.channel0;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//! This shows how to use the general purpose timers ETM tasks and events
|
||||
//! Notice you need to import the traits esp_hal::timer::etm::{TimerEtmEvents, TimerEtmTasks}
|
||||
//! Notice you need to import the traits esp_hal::timer::etm::{Events, Tasks}
|
||||
|
||||
//% CHIPS: esp32c6 esp32h2
|
||||
|
||||
@ -16,7 +16,7 @@ use esp_hal::{
|
||||
peripherals::TIMG0,
|
||||
prelude::*,
|
||||
timer::timg::{
|
||||
etm::{TimerEtmEvents, TimerEtmTasks},
|
||||
etm::{Events, Tasks},
|
||||
Timer,
|
||||
Timer0,
|
||||
TimerGroup,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user