1#![doc = crate::before_snippet!()]
28use core::marker::PhantomData;
55
56use crate::{
57 gpio::{
58 Level,
59 Pull,
60 interconnect::{InputSignal, OutputSignal},
61 },
62 peripherals::GPIO_SD,
63 private,
64};
65
66#[non_exhaustive]
68pub struct Channels<'d> {
69 _gpio_sd: GPIO_SD<'d>,
70 pub channel0_task: TaskChannel<0>,
72 pub channel0_event: EventChannel<0>,
74 pub channel1_task: TaskChannel<1>,
76 pub channel1_event: EventChannel<1>,
78 pub channel2_task: TaskChannel<2>,
80 pub channel2_event: EventChannel<2>,
82 pub channel3_task: TaskChannel<3>,
84 pub channel3_event: EventChannel<3>,
86 pub channel4_task: TaskChannel<4>,
88 pub channel4_event: EventChannel<4>,
90 pub channel5_task: TaskChannel<5>,
92 pub channel5_event: EventChannel<5>,
94 pub channel6_task: TaskChannel<6>,
96 pub channel6_event: EventChannel<6>,
98 pub channel7_task: TaskChannel<7>,
100 pub channel7_event: EventChannel<7>,
102}
103
104impl<'d> Channels<'d> {
105 pub fn new(peripheral: GPIO_SD<'d>) -> Self {
107 Self {
108 _gpio_sd: peripheral,
109 channel0_task: TaskChannel {},
110 channel0_event: EventChannel {},
111 channel1_task: TaskChannel {},
112 channel1_event: EventChannel {},
113 channel2_task: TaskChannel {},
114 channel2_event: EventChannel {},
115 channel3_task: TaskChannel {},
116 channel3_event: EventChannel {},
117 channel4_task: TaskChannel {},
118 channel4_event: EventChannel {},
119 channel5_task: TaskChannel {},
120 channel5_event: EventChannel {},
121 channel6_task: TaskChannel {},
122 channel6_event: EventChannel {},
123 channel7_task: TaskChannel {},
124 channel7_event: EventChannel {},
125 }
126 }
127}
128
129#[derive(Clone, Copy, Debug)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub struct InputConfig {
134 pub pull: Pull,
136}
137
138impl Default for InputConfig {
139 fn default() -> Self {
140 Self { pull: Pull::None }
141 }
142}
143
144pub struct EventChannel<const C: u8> {}
146
147impl<const C: u8> EventChannel<C> {
148 pub fn rising_edge<'d>(
150 self,
151 pin: impl Into<InputSignal<'d>>,
152 pin_config: InputConfig,
153 ) -> Event<'d> {
154 self.into_event(pin, pin_config, EventKind::Rising)
155 }
156
157 pub fn falling_edge<'d>(
159 self,
160 pin: impl Into<InputSignal<'d>>,
161 pin_config: InputConfig,
162 ) -> Event<'d> {
163 self.into_event(pin, pin_config, EventKind::Falling)
164 }
165
166 pub fn any_edge<'d>(
168 self,
169 pin: impl Into<InputSignal<'d>>,
170 pin_config: InputConfig,
171 ) -> Event<'d> {
172 self.into_event(pin, pin_config, EventKind::Any)
173 }
174
175 fn into_event<'d>(
176 self,
177 pin: impl Into<InputSignal<'d>>,
178 pin_config: InputConfig,
179 kind: EventKind,
180 ) -> Event<'d> {
181 let pin = pin.into();
182 if let Some(number) = pin.gpio_number() {
183 pin.apply_input_config(&crate::gpio::InputConfig::default().with_pull(pin_config.pull));
184 pin.set_input_enable(true);
185
186 enable_event_channel(C, number);
187 }
188 Event {
189 id: kind.id() + C,
190 _pin: PhantomData,
191 }
192 }
193}
194
195#[derive(Clone, Copy, Debug)]
196#[cfg_attr(feature = "defmt", derive(defmt::Format))]
197enum EventKind {
198 Rising,
199 Falling,
200 Any,
201}
202
203impl EventKind {
204 fn id(&self) -> u8 {
205 match self {
206 EventKind::Rising => 1,
207 EventKind::Falling => 9,
208 EventKind::Any => 17,
209 }
210 }
211}
212
213pub struct Event<'d> {
215 _pin: PhantomData<&'d mut ()>,
216 id: u8,
217}
218
219impl private::Sealed for Event<'_> {}
220
221impl crate::etm::EtmEvent for Event<'_> {
222 fn id(&self) -> u8 {
223 self.id
224 }
225}
226
227#[derive(Clone, Copy, Debug)]
229#[cfg_attr(feature = "defmt", derive(defmt::Format))]
230pub struct OutputConfig {
231 pub open_drain: bool,
233 pub pull: Pull,
235 pub initial_state: Level,
237}
238
239impl Default for OutputConfig {
240 fn default() -> Self {
241 Self {
242 open_drain: false,
243 pull: Pull::None,
244 initial_state: Level::Low,
245 }
246 }
247}
248
249pub struct TaskChannel<const C: u8> {}
251
252impl<const C: u8> TaskChannel<C> {
253 pub fn set<'d>(self, pin: impl Into<OutputSignal<'d>>, pin_config: OutputConfig) -> Task<'d> {
260 self.into_task(pin, pin_config, TaskKind::Set)
261 }
262
263 pub fn clear<'d>(self, pin: impl Into<OutputSignal<'d>>, pin_config: OutputConfig) -> Task<'d> {
265 self.into_task(pin, pin_config, TaskKind::Clear)
266 }
267
268 pub fn toggle<'d>(
270 self,
271 pin: impl Into<OutputSignal<'d>>,
272 pin_config: OutputConfig,
273 ) -> Task<'d> {
274 self.into_task(pin, pin_config, TaskKind::Toggle)
275 }
276
277 fn into_task<'d>(
278 self,
279 pin: impl Into<OutputSignal<'d>>,
280 pin_config: OutputConfig,
281 kind: TaskKind,
282 ) -> Task<'d> {
283 let pin = pin.into();
284
285 if let Some(number) = pin.gpio_number() {
286 let config = if pin_config.open_drain {
287 super::OutputConfig::default()
288 .with_drive_mode(super::DriveMode::OpenDrain)
289 .with_pull(pin_config.pull)
290 } else {
291 super::OutputConfig::default()
292 };
293
294 pin.set_output_high(pin_config.initial_state.into());
295 pin.apply_output_config(&config);
296 pin.set_output_enable(true);
297
298 enable_task_channel(C, number);
300 }
301 Task {
302 id: kind.id() + C,
303 _pin: PhantomData,
304 }
305 }
306}
307
308#[derive(Clone, Copy, Debug)]
309#[cfg_attr(feature = "defmt", derive(defmt::Format))]
310enum TaskKind {
311 Set,
312 Clear,
313 Toggle,
314}
315
316impl TaskKind {
317 fn id(&self) -> u8 {
318 match self {
319 TaskKind::Set => 1,
320 TaskKind::Clear => 9,
321 TaskKind::Toggle => 17,
322 }
323 }
324}
325
326pub struct Task<'d> {
328 _pin: PhantomData<&'d mut ()>,
329 id: u8,
330}
331
332impl private::Sealed for Task<'_> {}
333
334impl crate::etm::EtmTask for Task<'_> {
335 fn id(&self) -> u8 {
336 self.id
337 }
338}
339
340fn enable_task_channel(channel: u8, pin: u8) {
341 let gpio_sd = GPIO_SD::regs();
342 let ptr = unsafe { gpio_sd.etm_task_p0_cfg().as_ptr().add(pin as usize / 4) };
343 let shift = 8 * (pin as usize % 4);
344 unsafe {
346 ptr.write_volatile(
347 ptr.read_volatile() & !(0xf << shift)
348 | (1 << shift)
349 | ((channel as u32) << (shift + 1)),
350 );
351 }
352}
353
354fn enable_event_channel(channel: u8, pin: u8) {
355 let gpio_sd = GPIO_SD::regs();
356 gpio_sd
357 .etm_event_ch_cfg(channel as usize)
358 .modify(|_, w| w.event_en().clear_bit());
359 gpio_sd
360 .etm_event_ch_cfg(channel as usize)
361 .modify(|_, w| unsafe { w.event_sel().bits(pin) });
362 gpio_sd
363 .etm_event_ch_cfg(channel as usize)
364 .modify(|_, w| w.event_en().set_bit());
365}