1use embassy_rp::dma::{self, ChannelInstance};
35use embassy_rp::interrupt::typelevel::Binding;
36use embassy_rp::peripherals::{
37 DMA_CH0, DMA_CH1, DMA_CH2, DMA_CH3, DMA_CH4, DMA_CH5, DMA_CH6, DMA_CH7, DMA_CH8, DMA_CH9,
38 DMA_CH10, DMA_CH11, DMA_CH12, DMA_CH13, DMA_CH14, DMA_CH15, I2C0, I2C1, PIO0, PIO1, PIO2, SPI0,
39 SPI1, UART0, UART1,
40};
41use embassy_rp::pio::PioPin;
42use embassy_rp::spi::{self, ClkPin, MisoPin, MosiPin};
43use embassy_rp::{Peri, i2c, uart};
44
45use alloc::boxed::Box;
46
47use crate::bus::i2c::I2cBusHandle;
48use crate::bus::i2c_bitbang::BitBangI2cBus;
49use crate::bus::i2c_hardware::HardwareI2cBus;
50use crate::bus::pio::{PioManager, gpio_base_for_pins, spi_program_instructions};
51use crate::bus::spi::{SpiBusHandle, SpiError};
52use crate::bus::spi_bitbang::BitBangSpiBus;
53use crate::bus::spi_hardware::HardwareSpiBus;
54use crate::bus::uart::UartBusHandle;
55use crate::bus::uart_bitbang::BitBangUartBus;
56use crate::bus::uart_hardware::HardwareUartBus;
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
59pub enum AllocatorError {
61 Exhausted,
64 InvalidConfiguration,
66}
67
68impl From<SpiError> for AllocatorError {
69 fn from(_: SpiError) -> Self {
70 Self::InvalidConfiguration
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75#[repr(u8)]
76pub enum PioBlock {
78 Block0 = 0,
79 Block1 = 1,
80 Block2 = 2,
81}
82
83impl PioBlock {
84 pub const ALL: [PioBlock; 3] = [PioBlock::Block0, PioBlock::Block1, PioBlock::Block2];
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89#[repr(u8)]
90pub enum Sm {
92 Sm0 = 0,
94 Sm1 = 1,
96 Sm2 = 2,
98 Sm3 = 3,
100}
101
102impl Sm {
103 pub const ALL: [Sm; 4] = [Sm::Sm0, Sm::Sm1, Sm::Sm2, Sm::Sm3];
105}
106
107mod private {
115 pub trait Sealed {}
116 impl Sealed for super::SPI0 {}
117 impl Sealed for super::SPI1 {}
118 impl Sealed for super::I2C0 {}
119 impl Sealed for super::I2C1 {}
120 impl Sealed for super::UART0 {}
121 impl Sealed for super::UART1 {}
122 impl Sealed for super::DMA_CH0 {}
123 impl Sealed for super::DMA_CH1 {}
124 impl Sealed for super::DMA_CH2 {}
125 impl Sealed for super::DMA_CH3 {}
126 impl Sealed for super::DMA_CH4 {}
127 impl Sealed for super::DMA_CH5 {}
128 impl Sealed for super::DMA_CH6 {}
129 impl Sealed for super::DMA_CH7 {}
130 impl Sealed for super::DMA_CH8 {}
131 impl Sealed for super::DMA_CH9 {}
132 impl Sealed for super::DMA_CH10 {}
133 impl Sealed for super::DMA_CH11 {}
134 impl Sealed for super::DMA_CH12 {}
135 impl Sealed for super::DMA_CH13 {}
136 impl Sealed for super::DMA_CH14 {}
137 impl Sealed for super::DMA_CH15 {}
138}
139
140pub trait SpiHw: spi::Instance + private::Sealed + Send + 'static {
142 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>>;
143 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>);
144}
145
146pub trait I2cHw: i2c::Instance + private::Sealed + Send + 'static {
148 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>>;
149 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>);
150}
151
152pub trait UartHw: uart::Instance + private::Sealed + Send + 'static {
154 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>>;
155 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>);
156}
157
158pub trait DmaChannel: ChannelInstance + private::Sealed + 'static {
162 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>>;
163 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>);
164}
165
166impl SpiHw for SPI0 {
169 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
170 alloc.spi0_peri.take()
171 }
172 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
173 alloc.spi0_peri = Some(peri);
174 }
175}
176
177impl SpiHw for SPI1 {
178 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
179 alloc.spi1_peri.take()
180 }
181 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
182 alloc.spi1_peri = Some(peri);
183 }
184}
185
186impl I2cHw for I2C0 {
189 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
190 alloc.i2c0_peri.take()
191 }
192 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
193 alloc.i2c0_peri = Some(peri);
194 }
195}
196
197impl I2cHw for I2C1 {
198 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
199 alloc.i2c1_peri.take()
200 }
201 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
202 alloc.i2c1_peri = Some(peri);
203 }
204}
205
206impl UartHw for UART0 {
209 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
210 alloc.uart0_peri.take()
211 }
212 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
213 alloc.uart0_peri = Some(peri);
214 }
215}
216
217impl UartHw for UART1 {
218 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
219 alloc.uart1_peri.take()
220 }
221 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
222 alloc.uart1_peri = Some(peri);
223 }
224}
225
226macro_rules! impl_dma_channel {
229 ($($ch:ident => $field:ident),* $(,)?) => {
230 $(
231 impl DmaChannel for $ch {
232 fn take_peri(alloc: &mut BusAllocator) -> Option<Peri<'static, Self>> {
233 alloc.$field.take()
234 }
235 fn return_peri(alloc: &mut BusAllocator, peri: Peri<'static, Self>) {
236 alloc.$field = Some(peri);
237 }
238 }
239 )*
240 };
241}
242
243impl_dma_channel! {
244 DMA_CH0 => dma_ch0, DMA_CH1 => dma_ch1, DMA_CH2 => dma_ch2, DMA_CH3 => dma_ch3,
245 DMA_CH4 => dma_ch4, DMA_CH5 => dma_ch5, DMA_CH6 => dma_ch6, DMA_CH7 => dma_ch7,
246 DMA_CH8 => dma_ch8, DMA_CH9 => dma_ch9, DMA_CH10 => dma_ch10, DMA_CH11 => dma_ch11,
247 DMA_CH12 => dma_ch12, DMA_CH13 => dma_ch13, DMA_CH14 => dma_ch14, DMA_CH15 => dma_ch15,
248}
249
250pub struct BusAllocator {
251 spi0_peri: Option<Peri<'static, SPI0>>,
252 spi1_peri: Option<Peri<'static, SPI1>>,
253 i2c0_peri: Option<Peri<'static, I2C0>>,
254 i2c1_peri: Option<Peri<'static, I2C1>>,
255 uart0_peri: Option<Peri<'static, UART0>>,
256 uart1_peri: Option<Peri<'static, UART1>>,
257 dma_ch0: Option<Peri<'static, DMA_CH0>>,
258 dma_ch1: Option<Peri<'static, DMA_CH1>>,
259 dma_ch2: Option<Peri<'static, DMA_CH2>>,
260 dma_ch3: Option<Peri<'static, DMA_CH3>>,
261 dma_ch4: Option<Peri<'static, DMA_CH4>>,
262 dma_ch5: Option<Peri<'static, DMA_CH5>>,
263 dma_ch6: Option<Peri<'static, DMA_CH6>>,
264 dma_ch7: Option<Peri<'static, DMA_CH7>>,
265 dma_ch8: Option<Peri<'static, DMA_CH8>>,
266 dma_ch9: Option<Peri<'static, DMA_CH9>>,
267 dma_ch10: Option<Peri<'static, DMA_CH10>>,
268 dma_ch11: Option<Peri<'static, DMA_CH11>>,
269 dma_ch12: Option<Peri<'static, DMA_CH12>>,
270 dma_ch13: Option<Peri<'static, DMA_CH13>>,
271 dma_ch14: Option<Peri<'static, DMA_CH14>>,
272 dma_ch15: Option<Peri<'static, DMA_CH15>>,
273 pio_manager: PioManager,
274}
275
276pub struct DmaPool {
279 pub ch0: Option<Peri<'static, DMA_CH0>>,
280 pub ch1: Option<Peri<'static, DMA_CH1>>,
281 pub ch2: Option<Peri<'static, DMA_CH2>>,
282 pub ch3: Option<Peri<'static, DMA_CH3>>,
283 pub ch4: Option<Peri<'static, DMA_CH4>>,
284 pub ch5: Option<Peri<'static, DMA_CH5>>,
285 pub ch6: Option<Peri<'static, DMA_CH6>>,
286 pub ch7: Option<Peri<'static, DMA_CH7>>,
287 pub ch8: Option<Peri<'static, DMA_CH8>>,
288 pub ch9: Option<Peri<'static, DMA_CH9>>,
289 pub ch10: Option<Peri<'static, DMA_CH10>>,
290 pub ch11: Option<Peri<'static, DMA_CH11>>,
291 pub ch12: Option<Peri<'static, DMA_CH12>>,
292 pub ch13: Option<Peri<'static, DMA_CH13>>,
293 pub ch14: Option<Peri<'static, DMA_CH14>>,
294 pub ch15: Option<Peri<'static, DMA_CH15>>,
295}
296
297impl DmaPool {
298 pub const fn none() -> Self {
299 Self {
300 ch0: None,
301 ch1: None,
302 ch2: None,
303 ch3: None,
304 ch4: None,
305 ch5: None,
306 ch6: None,
307 ch7: None,
308 ch8: None,
309 ch9: None,
310 ch10: None,
311 ch11: None,
312 ch12: None,
313 ch13: None,
314 ch14: None,
315 ch15: None,
316 }
317 }
318}
319
320impl BusAllocator {
321 pub fn new(
347 spi0: Option<Peri<'static, SPI0>>,
348 spi1: Option<Peri<'static, SPI1>>,
349 i2c0: Option<Peri<'static, I2C0>>,
350 i2c1: Option<Peri<'static, I2C1>>,
351 uart0: Option<Peri<'static, UART0>>,
352 uart1: Option<Peri<'static, UART1>>,
353 dma: DmaPool,
354 pio0: Peri<'static, PIO0>,
355 pio1: Peri<'static, PIO1>,
356 pio2: Peri<'static, PIO2>,
357 ) -> Self {
358 Self {
359 spi0_peri: spi0,
360 spi1_peri: spi1,
361 i2c0_peri: i2c0,
362 i2c1_peri: i2c1,
363 uart0_peri: uart0,
364 uart1_peri: uart1,
365 dma_ch0: dma.ch0,
366 dma_ch1: dma.ch1,
367 dma_ch2: dma.ch2,
368 dma_ch3: dma.ch3,
369 dma_ch4: dma.ch4,
370 dma_ch5: dma.ch5,
371 dma_ch6: dma.ch6,
372 dma_ch7: dma.ch7,
373 dma_ch8: dma.ch8,
374 dma_ch9: dma.ch9,
375 dma_ch10: dma.ch10,
376 dma_ch11: dma.ch11,
377 dma_ch12: dma.ch12,
378 dma_ch13: dma.ch13,
379 dma_ch14: dma.ch14,
380 dma_ch15: dma.ch15,
381 pio_manager: PioManager::new(pio0, pio1, pio2),
382 }
383 }
384
385 pub fn request_spi_hardware<I: SpiHw>(&mut self) -> Result<Peri<'static, I>, AllocatorError> {
392 I::take_peri(self).ok_or(AllocatorError::Exhausted)
393 }
394
395 pub fn release_spi_hardware<I: SpiHw>(&mut self, peri: Peri<'static, I>) {
397 I::return_peri(self, peri);
398 }
399
400 pub fn request_dma<C: DmaChannel>(&mut self) -> Result<Peri<'static, C>, AllocatorError> {
405 C::take_peri(self).ok_or(AllocatorError::Exhausted)
406 }
407
408 pub fn release_dma<C: DmaChannel>(&mut self, peri: Peri<'static, C>) {
410 C::return_peri(self, peri);
411 }
412
413 pub fn create_spi_hardware<I, TxDma, RxDma, Irq>(
447 &mut self,
448 clk: Peri<'static, impl ClkPin<I>>,
449 mosi: Peri<'static, impl MosiPin<I>>,
450 miso: Peri<'static, impl MisoPin<I>>,
451 irq: Irq,
452 config: spi::Config,
453 ) -> Result<SpiBusHandle, AllocatorError>
454 where
455 I: SpiHw,
456 TxDma: DmaChannel,
457 RxDma: DmaChannel,
458 Irq: Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
459 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
460 + 'static,
461 {
462 HardwareSpiBus::<I>::validate_config(&config)
463 .map_err(|_| AllocatorError::InvalidConfiguration)?;
464 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
465 return Err(AllocatorError::InvalidConfiguration);
466 }
467
468 let peri = self.request_spi_hardware::<I>()?;
469 let tx_dma = match self.request_dma::<TxDma>() {
470 Ok(tx_dma) => tx_dma,
471 Err(error) => {
472 self.release_spi_hardware(peri);
473 return Err(error);
474 }
475 };
476 let rx_dma = match self.request_dma::<RxDma>() {
477 Ok(rx_dma) => rx_dma,
478 Err(error) => {
479 self.release_dma(tx_dma);
480 self.release_spi_hardware(peri);
481 return Err(error);
482 }
483 };
484 let bus = HardwareSpiBus::new(peri, clk, mosi, miso, tx_dma, rx_dma, irq, config)
485 .expect("SPI configuration was validated before allocation");
486 Ok(SpiBusHandle::new(
487 Box::new(bus),
488 crate::bus::spi::SpiBusVersion::Hardware,
489 ))
490 }
491
492 pub fn create_spi_pio<TxDma, RxDma, Irq>(
502 &mut self,
503 clk: Peri<'static, impl PioPin>,
504 mosi: Peri<'static, impl PioPin>,
505 miso: Peri<'static, impl PioPin>,
506 irq: Irq,
507 config: spi::Config,
508 ) -> Result<SpiBusHandle, AllocatorError>
509 where
510 TxDma: DmaChannel,
511 RxDma: DmaChannel,
512 Irq: Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
513 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
514 + 'static,
515 {
516 crate::bus::spi_pio::PioSpiBus::<PIO0, 0>::validate_config(&config)
517 .map_err(|_| AllocatorError::InvalidConfiguration)?;
518 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
519 return Err(AllocatorError::InvalidConfiguration);
520 }
521
522 let gpio_base_high = gpio_base_for_pins(&[clk.pin(), mosi.pin(), miso.pin()])
523 .ok_or(AllocatorError::InvalidConfiguration)?;
524 let instructions = spi_program_instructions(&config);
525 let (block, sm) = self
526 .pio_manager
527 .find_free_sm(gpio_base_high, instructions)
528 .ok_or(AllocatorError::Exhausted)?;
529 let tx_dma = self.request_dma::<TxDma>()?;
530 let rx_dma = match self.request_dma::<RxDma>() {
531 Ok(rx_dma) => rx_dma,
532 Err(error) => {
533 self.release_dma(tx_dma);
534 return Err(error);
535 }
536 };
537 Ok(self.pio_manager.build_spi_at(
538 block,
539 sm,
540 gpio_base_high,
541 instructions,
542 clk,
543 mosi,
544 miso,
545 tx_dma,
546 rx_dma,
547 irq,
548 config,
549 ))
550 }
551
552 pub fn create_spi_bitbang(
559 &mut self,
560 clk: Peri<'static, impl embassy_rp::gpio::Pin>,
561 mosi: Peri<'static, impl embassy_rp::gpio::Pin>,
562 miso: Peri<'static, impl embassy_rp::gpio::Pin>,
563 config: spi::Config,
564 ) -> Result<SpiBusHandle, AllocatorError> {
565 BitBangSpiBus::validate_config(&config)
566 .map_err(|_| AllocatorError::InvalidConfiguration)?;
567 let bus = BitBangSpiBus::new(clk, mosi, miso, config)
568 .map_err(|_| AllocatorError::InvalidConfiguration)?;
569 Ok(SpiBusHandle::new(
570 Box::new(bus),
571 crate::bus::spi::SpiBusVersion::BitBang,
572 ))
573 }
574
575 pub fn create_spi_no_hardware<TxDma, RxDma, Irq>(
584 &mut self,
585 clk: Peri<'static, impl PioPin>,
586 mosi: Peri<'static, impl PioPin>,
587 miso: Peri<'static, impl PioPin>,
588 irq: Irq,
589 config: spi::Config,
590 ) -> Result<SpiBusHandle, AllocatorError>
591 where
592 TxDma: DmaChannel,
593 RxDma: DmaChannel,
594 Irq: Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
595 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
596 + 'static,
597 {
598 crate::bus::spi_pio::PioSpiBus::<PIO0, 0>::validate_config(&config)
599 .map_err(|_| AllocatorError::InvalidConfiguration)?;
600 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
601 return Err(AllocatorError::InvalidConfiguration);
602 }
603
604 let gpio_base_high = gpio_base_for_pins(&[clk.pin(), mosi.pin(), miso.pin()])
605 .ok_or(AllocatorError::InvalidConfiguration);
606 let instructions = spi_program_instructions(&config);
607 let tx_dma = self.request_dma::<TxDma>();
608 let rx_dma = self.request_dma::<RxDma>();
609
610 match (gpio_base_high, tx_dma, rx_dma) {
611 (Ok(gpio_base_high), Ok(tx_dma), Ok(rx_dma)) => {
612 if let Ok((block, sm)) = self
613 .pio_manager
614 .find_free_sm(gpio_base_high, instructions)
615 .ok_or(AllocatorError::Exhausted)
616 {
617 return Ok(self.pio_manager.build_spi_at(
618 block,
619 sm,
620 gpio_base_high,
621 instructions,
622 clk,
623 mosi,
624 miso,
625 tx_dma,
626 rx_dma,
627 irq,
628 config,
629 ));
630 }
631 }
632 (_, tx_dma, rx_dma) => {
633 if let Ok(tx_dma) = tx_dma {
634 self.release_dma(tx_dma);
635 }
636
637 if let Ok(rx_dma) = rx_dma {
638 self.release_dma(rx_dma);
639 }
640 }
641 }
642
643 self.create_spi_bitbang(clk, mosi, miso, config)
644 }
645
646 pub fn create_spi<I, TxDma, RxDma, Irq>(
657 &mut self,
658 clk: Peri<'static, impl ClkPin<I> + PioPin>,
659 mosi: Peri<'static, impl MosiPin<I> + PioPin>,
660 miso: Peri<'static, impl MisoPin<I> + PioPin>,
661 irq: Irq,
662 config: spi::Config,
663 ) -> Result<SpiBusHandle, AllocatorError>
664 where
665 I: SpiHw,
666 TxDma: DmaChannel,
667 RxDma: DmaChannel,
668 Irq: Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
669 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
670 + 'static,
671 {
672 HardwareSpiBus::<I>::validate_config(&config)
673 .map_err(|_| AllocatorError::InvalidConfiguration)?;
674 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
675 return Err(AllocatorError::InvalidConfiguration);
676 }
677
678 let peri = self.request_spi_hardware::<I>();
679 let tx_dma = self.request_dma::<TxDma>();
680 let rx_dma = self.request_dma::<RxDma>();
681
682 match (peri, tx_dma, rx_dma) {
683 (Ok(peri), Ok(tx_dma), Ok(rx_dma)) => {
684 let bus = HardwareSpiBus::new(peri, clk, mosi, miso, tx_dma, rx_dma, irq, config)
685 .expect("SPI configuration was validated before allocation");
686 Ok(SpiBusHandle::new(
687 Box::new(bus),
688 crate::bus::spi::SpiBusVersion::Hardware,
689 ))
690 }
691 (peri, tx_dma, rx_dma) => {
692 if let Ok(peri) = peri {
693 self.release_spi_hardware(peri);
694 }
695 if let Ok(tx_dma) = tx_dma {
696 self.release_dma(tx_dma);
697 }
698 if let Ok(rx_dma) = rx_dma {
699 self.release_dma(rx_dma);
700 }
701
702 self.create_spi_no_hardware::<TxDma, RxDma, Irq>(clk, mosi, miso, irq, config)
703 }
704 }
705 }
706
707 pub fn request_i2c_hardware<I: I2cHw>(&mut self) -> Result<Peri<'static, I>, AllocatorError> {
714 I::take_peri(self).ok_or(AllocatorError::Exhausted)
715 }
716
717 pub fn release_i2c_hardware<I: I2cHw>(&mut self, peri: Peri<'static, I>) {
719 I::return_peri(self, peri);
720 }
721
722 pub fn create_i2c_hardware<I, Irq>(
749 &mut self,
750 scl: Peri<'static, impl i2c::SclPin<I>>,
751 sda: Peri<'static, impl i2c::SdaPin<I>>,
752 irq: Irq,
753 config: i2c::Config,
754 ) -> Result<I2cBusHandle, AllocatorError>
755 where
756 I: I2cHw,
757 Irq: Binding<I::Interrupt, i2c::InterruptHandler<I>> + 'static,
758 {
759 HardwareI2cBus::<I>::validate_config(&config)
760 .map_err(|_| AllocatorError::InvalidConfiguration)?;
761 let peri = self.request_i2c_hardware::<I>()?;
762 let bus = HardwareI2cBus::new(peri, scl, sda, irq, config)
763 .expect("I2C configuration was validated before allocation");
764 Ok(I2cBusHandle::new(
765 Box::new(bus),
766 crate::bus::i2c::I2cBusVersion::Hardware,
767 ))
768 }
769
770 pub fn create_i2c_bitbang(
779 &mut self,
780 scl: Peri<'static, impl embassy_rp::gpio::Pin>,
781 sda: Peri<'static, impl embassy_rp::gpio::Pin>,
782 frequency_hz: u32,
783 ) -> Result<I2cBusHandle, AllocatorError> {
784 let bus = BitBangI2cBus::new(scl, sda, frequency_hz)
785 .map_err(|_| AllocatorError::InvalidConfiguration)?;
786 Ok(I2cBusHandle::new(
787 Box::new(bus),
788 crate::bus::i2c::I2cBusVersion::BitBang,
789 ))
790 }
791
792 pub fn request_uart_hardware<I: UartHw>(&mut self) -> Result<Peri<'static, I>, AllocatorError> {
799 I::take_peri(self).ok_or(AllocatorError::Exhausted)
800 }
801
802 pub fn release_uart_hardware<I: UartHw>(&mut self, peri: Peri<'static, I>) {
804 I::return_peri(self, peri);
805 }
806
807 pub fn create_uart_hardware<I, TxDma, RxDma, Irq>(
819 &mut self,
820 tx: Peri<'static, impl uart::TxPin<I>>,
821 rx: Peri<'static, impl uart::RxPin<I>>,
822 irq: Irq,
823 config: uart::Config,
824 ) -> Result<UartBusHandle, AllocatorError>
825 where
826 I: UartHw,
827 TxDma: DmaChannel,
828 RxDma: DmaChannel,
829 Irq: Binding<I::Interrupt, uart::InterruptHandler<I>>
830 + Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
831 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
832 + 'static,
833 {
834 HardwareUartBus::validate_config(&config)
835 .map_err(|_| AllocatorError::InvalidConfiguration)?;
836 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
837 return Err(AllocatorError::InvalidConfiguration);
838 }
839
840 let peri = self.request_uart_hardware::<I>()?;
841 let tx_dma = match self.request_dma::<TxDma>() {
842 Ok(tx_dma) => tx_dma,
843 Err(error) => {
844 self.release_uart_hardware(peri);
845 return Err(error);
846 }
847 };
848 let rx_dma = match self.request_dma::<RxDma>() {
849 Ok(rx_dma) => rx_dma,
850 Err(error) => {
851 self.release_dma(tx_dma);
852 self.release_uart_hardware(peri);
853 return Err(error);
854 }
855 };
856 let bus = HardwareUartBus::new(peri, tx, rx, irq, tx_dma, rx_dma, config)
857 .expect("UART configuration was validated before allocation");
858 Ok(UartBusHandle::new(
859 Box::new(bus),
860 crate::bus::uart::UartBusVersion::Hardware,
861 ))
862 }
863
864 pub fn create_uart_pio(
874 &mut self,
875 tx: Peri<'static, impl PioPin>,
876 rx: Peri<'static, impl PioPin>,
877 baud_rate: u32,
878 ) -> Result<UartBusHandle, AllocatorError> {
879 crate::bus::uart_pio::PioUartBus::<PIO0, 0, 1>::validate_baud(baud_rate)
880 .map_err(|_| AllocatorError::InvalidConfiguration)?;
881 let gpio_base_high =
882 gpio_base_for_pins(&[tx.pin()]).ok_or(AllocatorError::InvalidConfiguration)?;
883 if gpio_base_for_pins(&[rx.pin()]) != Some(gpio_base_high) {
884 return Err(AllocatorError::InvalidConfiguration);
885 }
886 self.pio_manager
887 .build_uart_pio(tx, rx, baud_rate)
888 .ok_or(AllocatorError::Exhausted)
889 }
890
891 pub fn create_uart_bitbang(
900 &mut self,
901 tx: Peri<'static, impl embassy_rp::gpio::Pin>,
902 rx: Peri<'static, impl embassy_rp::gpio::Pin>,
903 baud_rate: u32,
904 ) -> Result<UartBusHandle, AllocatorError> {
905 BitBangUartBus::validate_baud(baud_rate)
906 .map_err(|_| AllocatorError::InvalidConfiguration)?;
907 let bus = BitBangUartBus::new(tx, rx, baud_rate)
908 .map_err(|_| AllocatorError::InvalidConfiguration)?;
909 Ok(UartBusHandle::new(
910 Box::new(bus),
911 crate::bus::uart::UartBusVersion::BitBang,
912 ))
913 }
914
915 pub fn create_uart_no_hardware(
928 &mut self,
929 tx: Peri<'static, impl PioPin>,
930 rx: Peri<'static, impl PioPin>,
931 baud_rate: u32,
932 ) -> Result<UartBusHandle, AllocatorError> {
933 crate::bus::uart_pio::PioUartBus::<PIO0, 0, 1>::validate_baud(baud_rate)
934 .map_err(|_| AllocatorError::InvalidConfiguration)?;
935
936 let tx_base = gpio_base_for_pins(&[tx.pin()]);
937 let rx_base = gpio_base_for_pins(&[rx.pin()]);
938 if let (Some(gpio_base_high), true) = (tx_base, tx_base == rx_base)
939 && let Some((block, sm_tx, sm_rx)) = self
940 .pio_manager
941 .find_free_sm_pair(gpio_base_high, crate::bus::pio::PIO_UART_INSTRUCTIONS)
942 {
943 return Ok(self.pio_manager.build_uart_at(
944 block,
945 sm_tx,
946 sm_rx,
947 gpio_base_high,
948 crate::bus::pio::PIO_UART_INSTRUCTIONS,
949 tx,
950 rx,
951 baud_rate,
952 ));
953 }
954 self.create_uart_bitbang(tx, rx, baud_rate)
955 }
956
957 pub fn create_uart<I, TxDma, RxDma, Irq>(
970 &mut self,
971 tx: Peri<'static, impl uart::TxPin<I> + PioPin>,
972 rx: Peri<'static, impl uart::RxPin<I> + PioPin>,
973 irq: Irq,
974 config: uart::Config,
975 ) -> Result<UartBusHandle, AllocatorError>
976 where
977 I: UartHw,
978 TxDma: DmaChannel,
979 RxDma: DmaChannel,
980 Irq: Binding<I::Interrupt, uart::InterruptHandler<I>>
981 + Binding<TxDma::Interrupt, dma::InterruptHandler<TxDma>>
982 + Binding<RxDma::Interrupt, dma::InterruptHandler<RxDma>>
983 + 'static,
984 {
985 HardwareUartBus::validate_config(&config)
986 .map_err(|_| AllocatorError::InvalidConfiguration)?;
987
988 if core::any::TypeId::of::<TxDma>() == core::any::TypeId::of::<RxDma>() {
989 return Err(AllocatorError::InvalidConfiguration);
990 }
991
992 let peri = self.request_uart_hardware::<I>();
993 let tx_dma = self.request_dma::<TxDma>();
994 let rx_dma = self.request_dma::<RxDma>();
995
996 match (peri, tx_dma, rx_dma) {
997 (Ok(peri), Ok(tx_dma), Ok(rx_dma)) => {
999 let bus = HardwareUartBus::new(peri, tx, rx, irq, tx_dma, rx_dma, config)
1000 .expect("UART configuration was validated before allocation");
1001
1002 Ok(UartBusHandle::new(
1003 Box::new(bus),
1004 crate::bus::uart::UartBusVersion::Hardware,
1005 ))
1006 }
1007
1008 (peri, tx_dma, rx_dma) => {
1011 if let Ok(peri) = peri {
1012 self.release_uart_hardware(peri);
1013 }
1014 if let Ok(tx_dma) = tx_dma {
1015 self.release_dma(tx_dma);
1016 }
1017 if let Ok(rx_dma) = rx_dma {
1018 self.release_dma(rx_dma);
1019 }
1020
1021 self.create_uart_no_hardware(tx, rx, config.baudrate)
1022 }
1023 }
1024 }
1025
1026 pub fn request_pio<P: PioPin>(
1042 &mut self,
1043 pin: &Peri<'static, P>,
1044 ) -> Option<crate::bus::pio::PioAccess<'_>> {
1045 self.pio_manager.request_pio(pin)
1046 }
1047}