aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/pio.rs438
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/pio_async.rs37
-rw-r--r--examples/rp/src/bin/pio_dma.rs27
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs42
-rw-r--r--examples/rp/src/bin/ws2812-pio.rs39
6 files changed, 300 insertions, 285 deletions
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 8d0547907..a1b7cf1c5 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -6,9 +6,13 @@ use core::task::{Context, Poll};
6 6
7use atomic_polyfill::{AtomicU32, AtomicU8}; 7use atomic_polyfill::{AtomicU32, AtomicU8};
8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 8use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
9use embassy_embedded_hal::SetConfig;
9use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 10use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
12use fixed::types::extra::U8;
13use fixed::FixedU32;
11use pac::io::vals::Gpio0ctrlFuncsel; 14use pac::io::vals::Gpio0ctrlFuncsel;
15use pac::pio::vals::SmExecctrlStatusSel;
12use pio::{SideSet, Wrap}; 16use pio::{SideSet, Wrap};
13 17
14use crate::dma::{Channel, Transfer, Word}; 18use crate::dma::{Channel, Transfer, Word};
@@ -39,8 +43,12 @@ const NEW_AW: AtomicWaker = AtomicWaker::new();
39const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); 43const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
40static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; 44static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2];
41 45
46#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48#[repr(u8)]
42pub enum FifoJoin { 49pub enum FifoJoin {
43 /// Both TX and RX fifo is enabled 50 /// Both TX and RX fifo is enabled
51 #[default]
44 Duplex, 52 Duplex,
45 /// Rx fifo twice as deep. TX fifo disabled 53 /// Rx fifo twice as deep. TX fifo disabled
46 RxOnly, 54 RxOnly,
@@ -48,8 +56,11 @@ pub enum FifoJoin {
48 TxOnly, 56 TxOnly,
49} 57}
50 58
51#[derive(PartialEq)] 59#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61#[repr(u8)]
52pub enum ShiftDirection { 62pub enum ShiftDirection {
63 #[default]
53 Right = 1, 64 Right = 1,
54 Left = 0, 65 Left = 0,
55} 66}
@@ -62,6 +73,15 @@ pub enum Direction {
62 Out = 1, 73 Out = 1,
63} 74}
64 75
76#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78#[repr(u8)]
79pub enum StatusSource {
80 #[default]
81 TxFifoLevel = 0,
82 RxFifoLevel = 1,
83}
84
65const RXNEMPTY_MASK: u32 = 1 << 0; 85const RXNEMPTY_MASK: u32 = 1 << 0;
66const TXNFULL_MASK: u32 = 1 << 4; 86const TXNFULL_MASK: u32 = 1 << 4;
67const SMIRQ_MASK: u32 = 1 << 8; 87const SMIRQ_MASK: u32 = 1 << 8;
@@ -477,6 +497,202 @@ fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) {
477 } 497 }
478} 498}
479 499
500#[derive(Clone, Copy, Default, Debug)]
501#[cfg_attr(feature = "defmt", derive(defmt::Format))]
502#[non_exhaustive]
503pub struct ExecConfig {
504 pub side_en: bool,
505 pub side_pindir: bool,
506 pub jmp_pin: u8,
507 pub wrap_top: u8,
508 pub wrap_bottom: u8,
509}
510
511#[derive(Clone, Copy, Default, Debug)]
512#[cfg_attr(feature = "defmt", derive(defmt::Format))]
513pub struct ShiftConfig {
514 pub threshold: u8,
515 pub direction: ShiftDirection,
516 pub auto_fill: bool,
517}
518
519#[derive(Clone, Copy, Default, Debug)]
520#[cfg_attr(feature = "defmt", derive(defmt::Format))]
521pub struct PinConfig {
522 pub sideset_count: u8,
523 pub set_count: u8,
524 pub out_count: u8,
525 pub in_base: u8,
526 pub sideset_base: u8,
527 pub set_base: u8,
528 pub out_base: u8,
529}
530
531#[derive(Clone, Copy, Debug)]
532pub struct Config<'d, PIO: Instance> {
533 // CLKDIV
534 pub clock_divider: FixedU32<U8>,
535 // EXECCTRL
536 pub out_en_sel: u8,
537 pub inline_out_en: bool,
538 pub out_sticky: bool,
539 pub status_sel: StatusSource,
540 pub status_n: u8,
541 exec: ExecConfig,
542 origin: Option<u8>,
543 // SHIFTCTRL
544 pub fifo_join: FifoJoin,
545 pub shift_in: ShiftConfig,
546 pub shift_out: ShiftConfig,
547 // PINCTRL
548 pins: PinConfig,
549 in_count: u8,
550 _pio: PhantomData<&'d mut PIO>,
551}
552
553impl<'d, PIO: Instance> Default for Config<'d, PIO> {
554 fn default() -> Self {
555 Self {
556 clock_divider: 1u8.into(),
557 out_en_sel: Default::default(),
558 inline_out_en: Default::default(),
559 out_sticky: Default::default(),
560 status_sel: Default::default(),
561 status_n: Default::default(),
562 exec: Default::default(),
563 origin: Default::default(),
564 fifo_join: Default::default(),
565 shift_in: Default::default(),
566 shift_out: Default::default(),
567 pins: Default::default(),
568 in_count: Default::default(),
569 _pio: Default::default(),
570 }
571 }
572}
573
574impl<'d, PIO: Instance> Config<'d, PIO> {
575 pub fn get_exec(&self) -> ExecConfig {
576 self.exec
577 }
578 pub unsafe fn set_exec(&mut self, e: ExecConfig) {
579 self.exec = e;
580 }
581
582 pub fn get_pins(&self) -> PinConfig {
583 self.pins
584 }
585 pub unsafe fn set_pins(&mut self, p: PinConfig) {
586 self.pins = p;
587 }
588
589 /// Configures this state machine to use the given program, including jumping to the origin
590 /// of the program. The state machine is not started.
591 ///
592 /// `side_set` sets the range of pins affected by side-sets. The range must be consecutive.
593 /// Side-set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
594 /// effective.
595 pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) {
596 assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len());
597 assert_consecutive(side_set);
598 self.exec.side_en = prog.side_set.optional();
599 self.exec.side_pindir = prog.side_set.pindirs();
600 self.exec.wrap_bottom = prog.wrap.target;
601 self.exec.wrap_top = prog.wrap.source;
602 self.pins.sideset_count = prog.side_set.bits();
603 self.pins.sideset_base = side_set.first().map_or(0, |p| p.pin());
604 self.origin = Some(prog.origin);
605 }
606
607 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) {
608 self.exec.jmp_pin = pin.pin();
609 }
610
611 /// Sets the range of pins affected by SET instructions. The range must be consecutive.
612 /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
613 /// effective.
614 pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
615 assert!(pins.len() <= 5);
616 assert_consecutive(pins);
617 self.pins.set_base = pins.first().map_or(0, |p| p.pin());
618 self.pins.set_count = pins.len() as u8;
619 }
620
621 /// Sets the range of pins affected by OUT instructions. The range must be consecutive.
622 /// Out pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be
623 /// effective.
624 pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
625 assert_consecutive(pins);
626 self.pins.out_base = pins.first().map_or(0, |p| p.pin());
627 self.pins.out_count = pins.len() as u8;
628 }
629
630 /// Sets the range of pins used by IN instructions. The range must be consecutive.
631 /// In pins must configured as inputs using [`StateMachine::set_pin_dirs`] to be
632 /// effective.
633 pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) {
634 assert_consecutive(pins);
635 self.pins.in_base = pins.first().map_or(0, |p| p.pin());
636 self.in_count = pins.len() as u8;
637 }
638}
639
640impl<'d, PIO: Instance, const SM: usize> SetConfig for StateMachine<'d, PIO, SM> {
641 type Config = Config<'d, PIO>;
642
643 fn set_config(&mut self, config: &Self::Config) {
644 // sm expects 0 for 65536, truncation makes that happen
645 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
646 assert!(config.clock_divider >= 1, "clkdiv must be >= 1");
647 assert!(config.out_en_sel < 32, "out_en_sel must be < 32");
648 assert!(config.status_n < 32, "status_n must be < 32");
649 // sm expects 0 for 32, truncation makes that happen
650 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
651 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
652 let sm = Self::this_sm();
653 unsafe {
654 sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
655 sm.execctrl().write(|w| {
656 w.set_side_en(config.exec.side_en);
657 w.set_side_pindir(config.exec.side_pindir);
658 w.set_jmp_pin(config.exec.jmp_pin);
659 w.set_out_en_sel(config.out_en_sel);
660 w.set_inline_out_en(config.inline_out_en);
661 w.set_out_sticky(config.out_sticky);
662 w.set_wrap_top(config.exec.wrap_top);
663 w.set_wrap_bottom(config.exec.wrap_bottom);
664 w.set_status_sel(match config.status_sel {
665 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
666 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
667 });
668 w.set_status_n(config.status_n);
669 });
670 sm.shiftctrl().write(|w| {
671 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
672 w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly);
673 w.set_pull_thresh(config.shift_out.threshold);
674 w.set_push_thresh(config.shift_in.threshold);
675 w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right);
676 w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right);
677 w.set_autopull(config.shift_out.auto_fill);
678 w.set_autopush(config.shift_in.auto_fill);
679 });
680 sm.pinctrl().write(|w| {
681 w.set_sideset_count(config.pins.sideset_count);
682 w.set_set_count(config.pins.set_count);
683 w.set_out_count(config.pins.out_count);
684 w.set_in_base(config.pins.in_base);
685 w.set_sideset_base(config.pins.sideset_base);
686 w.set_set_base(config.pins.set_base);
687 w.set_out_base(config.pins.out_base);
688 });
689 if let Some(origin) = config.origin {
690 pio_instr_util::exec_jmp(self, origin);
691 }
692 }
693 }
694}
695
480impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { 696impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
481 #[inline(always)] 697 #[inline(always)]
482 fn this_sm() -> crate::pac::pio::StateMachine { 698 fn this_sm() -> crate::pac::pio::StateMachine {
@@ -504,16 +720,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
504 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } 720 unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 }
505 } 721 }
506 722
507 pub fn set_clkdiv(&mut self, div_x_256: u32) {
508 unsafe {
509 Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8);
510 }
511 }
512
513 pub fn get_clkdiv(&self) -> u32 {
514 unsafe { Self::this_sm().clkdiv().read().0 >> 8 }
515 }
516
517 pub fn clkdiv_restart(&mut self) { 723 pub fn clkdiv_restart(&mut self) {
518 let mask = 1u8 << SM; 724 let mask = 1u8 << SM;
519 unsafe { 725 unsafe {
@@ -521,26 +727,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
521 } 727 }
522 } 728 }
523 729
524 /// Configures this state machine to use the given program, including jumping to the origin
525 /// of the program. The state machine is not started.
526 pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) {
527 assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len());
528 assert_consecutive(side_set);
529 unsafe {
530 Self::this_sm().execctrl().modify(|w| {
531 w.set_side_en(prog.side_set.optional());
532 w.set_side_pindir(prog.side_set.pindirs());
533 w.set_wrap_bottom(prog.wrap.target);
534 w.set_wrap_top(prog.wrap.source);
535 });
536 Self::this_sm().pinctrl().modify(|w| {
537 w.set_sideset_count(prog.side_set.bits());
538 w.set_sideset_base(side_set.first().map_or(0, |p| p.pin()));
539 });
540 pio_instr_util::exec_jmp(self, prog.origin);
541 }
542 }
543
544 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { 730 fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
545 let enabled = self.is_enabled(); 731 let enabled = self.is_enabled();
546 self.set_enable(false); 732 self.set_enable(false);
@@ -591,43 +777,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
591 }); 777 });
592 } 778 }
593 779
594 pub fn set_jmp_pin(&mut self, pin: u8) {
595 unsafe {
596 Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin));
597 }
598 }
599
600 pub fn get_jmp_pin(&mut self) -> u8 {
601 unsafe { Self::this_sm().execctrl().read().jmp_pin() }
602 }
603
604 pub fn set_fifo_join(&mut self, join: FifoJoin) {
605 let (rx, tx) = match join {
606 FifoJoin::Duplex => (false, false),
607 FifoJoin::RxOnly => (true, false),
608 FifoJoin::TxOnly => (false, true),
609 };
610 unsafe {
611 Self::this_sm().shiftctrl().modify(|w| {
612 w.set_fjoin_rx(rx);
613 w.set_fjoin_tx(tx)
614 });
615 }
616 }
617 pub fn get_fifo_join(&self) -> FifoJoin {
618 unsafe {
619 let r = Self::this_sm().shiftctrl().read();
620 // Ignores the invalid state when both bits are set
621 if r.fjoin_rx() {
622 FifoJoin::RxOnly
623 } else if r.fjoin_tx() {
624 FifoJoin::TxOnly
625 } else {
626 FifoJoin::Duplex
627 }
628 }
629 }
630
631 pub fn clear_fifos(&mut self) { 780 pub fn clear_fifos(&mut self) {
632 // Toggle FJOIN_RX to flush FIFOs 781 // Toggle FJOIN_RX to flush FIFOs
633 unsafe { 782 unsafe {
@@ -641,159 +790,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
641 } 790 }
642 } 791 }
643 792
644 pub fn set_pull_threshold(&mut self, threshold: u8) {
645 unsafe {
646 Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold));
647 }
648 }
649
650 pub fn get_pull_threshold(&self) -> u8 {
651 unsafe { Self::this_sm().shiftctrl().read().pull_thresh() }
652 }
653 pub fn set_push_threshold(&mut self, threshold: u8) {
654 unsafe {
655 Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold));
656 }
657 }
658
659 pub fn get_push_threshold(&self) -> u8 {
660 unsafe { Self::this_sm().shiftctrl().read().push_thresh() }
661 }
662
663 pub fn set_out_shift_dir(&mut self, dir: ShiftDirection) {
664 unsafe {
665 Self::this_sm()
666 .shiftctrl()
667 .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
668 }
669 }
670 pub fn get_out_shiftdir(&self) -> ShiftDirection {
671 unsafe {
672 if Self::this_sm().shiftctrl().read().out_shiftdir() {
673 ShiftDirection::Right
674 } else {
675 ShiftDirection::Left
676 }
677 }
678 }
679
680 pub fn set_in_shift_dir(&mut self, dir: ShiftDirection) {
681 unsafe {
682 Self::this_sm()
683 .shiftctrl()
684 .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
685 }
686 }
687 pub fn get_in_shiftdir(&self) -> ShiftDirection {
688 unsafe {
689 if Self::this_sm().shiftctrl().read().in_shiftdir() {
690 ShiftDirection::Right
691 } else {
692 ShiftDirection::Left
693 }
694 }
695 }
696
697 pub fn set_autopull(&mut self, auto: bool) {
698 unsafe {
699 Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto));
700 }
701 }
702
703 pub fn is_autopull(&self) -> bool {
704 unsafe { Self::this_sm().shiftctrl().read().autopull() }
705 }
706
707 pub fn set_autopush(&mut self, auto: bool) {
708 unsafe {
709 Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto));
710 }
711 }
712
713 pub fn is_autopush(&self) -> bool {
714 unsafe { Self::this_sm().shiftctrl().read().autopush() }
715 }
716
717 pub fn get_addr(&self) -> u8 {
718 unsafe { Self::this_sm().addr().read().addr() }
719 }
720
721 /// Set the range of out pins affected by a set instruction.
722 pub fn set_set_range(&mut self, base: u8, count: u8) {
723 assert!(base + count < 32);
724 unsafe {
725 Self::this_sm().pinctrl().modify(|w| {
726 w.set_set_base(base);
727 w.set_set_count(count)
728 });
729 }
730 }
731
732 /// Get the range of out pins affected by a set instruction. Returns (base, count).
733 pub fn get_set_range(&self) -> (u8, u8) {
734 unsafe {
735 let r = Self::this_sm().pinctrl().read();
736 (r.set_base(), r.set_count())
737 }
738 }
739
740 pub fn set_in_base_pin(&mut self, base: &Pin<PIO>) {
741 unsafe {
742 Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin()));
743 }
744 }
745
746 pub fn get_in_base(&self) -> u8 {
747 unsafe {
748 let r = Self::this_sm().pinctrl().read();
749 r.in_base()
750 }
751 }
752
753 pub fn set_out_range(&mut self, base: u8, count: u8) {
754 assert!(base + count < 32);
755 unsafe {
756 Self::this_sm().pinctrl().modify(|w| {
757 w.set_out_base(base);
758 w.set_out_count(count)
759 });
760 }
761 }
762
763 /// Get the range of out pins affected by a set instruction. Returns (base, count).
764 pub fn get_out_range(&self) -> (u8, u8) {
765 unsafe {
766 let r = Self::this_sm().pinctrl().read();
767 (r.out_base(), r.out_count())
768 }
769 }
770
771 pub fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin<PIO>]) {
772 let count = pins.len();
773 assert!(count >= 1);
774 let start = pins[0].pin() as usize;
775 assert!(start + pins.len() <= 32);
776 for i in 0..count {
777 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
778 }
779 self.set_out_range(start as u8, count as u8);
780 }
781
782 pub fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin<PIO>]) {
783 let count = pins.len();
784 assert!(count >= 1);
785 let start = pins[0].pin() as usize;
786 assert!(start + pins.len() <= 32);
787 for i in 0..count {
788 assert!(pins[i].pin() as usize == start + i, "Pins must be sequential");
789 }
790 self.set_set_range(start as u8, count as u8);
791 }
792
793 pub fn get_current_instr() -> u32 {
794 unsafe { Self::this_sm().instr().read().0 }
795 }
796
797 pub fn exec_instr(&mut self, instr: u16) { 793 pub fn exec_instr(&mut self, instr: u16) {
798 unsafe { 794 unsafe {
799 Self::this_sm().instr().write(|w| w.set_instr(instr)); 795 Self::this_sm().instr().write(|w| w.set_instr(instr));
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 57f6f5c67..d2829df99 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -22,6 +22,8 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr
22 22
23defmt = "0.3" 23defmt = "0.3"
24defmt-rtt = "0.4" 24defmt-rtt = "0.4"
25fixed = "1.23.1"
26fixed-macro = "1.2"
25 27
26#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 28#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
27cortex-m = { version = "0.7.6", features = ["inline-asm"] } 29cortex-m = { version = "0.7.6", features = ["inline-asm"] }
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
index 9f47c2316..12484e882 100644
--- a/examples/rp/src/bin/pio_async.rs
+++ b/examples/rp/src/bin/pio_async.rs
@@ -2,10 +2,13 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4use defmt::info; 4use defmt::info;
5use embassy_embedded_hal::SetConfig;
5use embassy_executor::Spawner; 6use embassy_executor::Spawner;
6use embassy_rp::peripherals::PIO0; 7use embassy_rp::peripherals::PIO0;
7use embassy_rp::pio::{Common, Irq, Pio, PioPin, ShiftDirection, StateMachine}; 8use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine};
8use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
10use fixed::traits::ToFixed;
11use fixed_macro::types::U56F8;
9use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
10 13
11fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { 14fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
@@ -21,15 +24,14 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
21 ); 24 );
22 25
23 let relocated = RelocatedProgram::new(&prg.program); 26 let relocated = RelocatedProgram::new(&prg.program);
24 sm.use_program(&pio.load_program(&relocated), &[]); 27 let mut cfg = Config::default();
28 cfg.use_program(&pio.load_program(&relocated), &[]);
25 let out_pin = pio.make_pio_pin(pin); 29 let out_pin = pio.make_pio_pin(pin);
26 let pio_pins = [&out_pin]; 30 cfg.set_out_pins(&[&out_pin]);
27 sm.set_out_pins(&pio_pins); 31 cfg.set_set_pins(&[&out_pin]);
28 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); 32 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
29 sm.set_set_range(0, 1); 33 cfg.shift_out.auto_fill = true;
30 34 sm.set_config(&cfg);
31 sm.set_autopull(true);
32 sm.set_out_shift_dir(ShiftDirection::Left);
33} 35}
34 36
35#[embassy_executor::task] 37#[embassy_executor::task]
@@ -51,11 +53,12 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
51 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); 53 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
52 54
53 let relocated = RelocatedProgram::new(&prg.program); 55 let relocated = RelocatedProgram::new(&prg.program);
54 sm.use_program(&pio.load_program(&relocated), &[]); 56 let mut cfg = Config::default();
55 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); 57 cfg.use_program(&pio.load_program(&relocated), &[]);
56 sm.set_set_range(0, 0); 58 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
57 sm.set_autopush(true); 59 cfg.shift_in.auto_fill = true;
58 sm.set_in_shift_dir(ShiftDirection::Right); 60 cfg.shift_in.direction = ShiftDirection::Right;
61 sm.set_config(&cfg);
59} 62}
60 63
61#[embassy_executor::task] 64#[embassy_executor::task]
@@ -81,8 +84,10 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a,
81 ".wrap", 84 ".wrap",
82 ); 85 );
83 let relocated = RelocatedProgram::new(&prg.program); 86 let relocated = RelocatedProgram::new(&prg.program);
84 sm.use_program(&pio.load_program(&relocated), &[]); 87 let mut cfg = Config::default();
85 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); 88 cfg.use_program(&pio.load_program(&relocated), &[]);
89 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
90 sm.set_config(&cfg);
86} 91}
87 92
88#[embassy_executor::task] 93#[embassy_executor::task]
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
index 1c4e127c7..7f85288bf 100644
--- a/examples/rp/src/bin/pio_dma.rs
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -2,11 +2,14 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4use defmt::info; 4use defmt::info;
5use embassy_embedded_hal::SetConfig;
5use embassy_executor::Spawner; 6use embassy_executor::Spawner;
6use embassy_futures::join::join; 7use embassy_futures::join::join;
7use embassy_rp::pio::{Pio, ShiftDirection}; 8use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection};
8use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
9use embassy_rp::Peripheral; 10use embassy_rp::Peripheral;
11use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8;
10use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
11 14
12fn swap_nibbles(v: u32) -> u32 { 15fn swap_nibbles(v: u32) -> u32 {
@@ -38,15 +41,21 @@ async fn main(_spawner: Spawner) {
38 ); 41 );
39 42
40 let relocated = RelocatedProgram::new(&prg.program); 43 let relocated = RelocatedProgram::new(&prg.program);
41 sm.use_program(&common.load_program(&relocated), &[]); 44 let mut cfg = Config::default();
42 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); 45 cfg.use_program(&common.load_program(&relocated), &[]);
43 sm.set_autopull(true); 46 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
44 sm.set_autopush(true); 47 cfg.shift_in = ShiftConfig {
45 sm.set_pull_threshold(32); 48 auto_fill: true,
46 sm.set_push_threshold(32); 49 threshold: 32,
47 sm.set_out_shift_dir(ShiftDirection::Right); 50 direction: ShiftDirection::Left,
48 sm.set_in_shift_dir(ShiftDirection::Left); 51 };
52 cfg.shift_out = ShiftConfig {
53 auto_fill: true,
54 threshold: 32,
55 direction: ShiftDirection::Right,
56 };
49 57
58 sm.set_config(&cfg);
50 sm.set_enable(true); 59 sm.set_enable(true);
51 60
52 let mut dma_out_ref = p.DMA_CH0.into_ref(); 61 let mut dma_out_ref = p.DMA_CH0.into_ref();
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
index 40dee1c4d..61c5565d3 100644
--- a/examples/rp/src/bin/pio_hd44780.rs
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -4,11 +4,12 @@
4 4
5use core::fmt::Write; 5use core::fmt::Write;
6 6
7use embassy_embedded_hal::SetConfig;
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
8use embassy_rp::dma::{AnyChannel, Channel}; 9use embassy_rp::dma::{AnyChannel, Channel};
9use embassy_rp::peripherals::PIO0; 10use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Direction, FifoJoin, Pio, PioPin, ShiftDirection, StateMachine}; 11use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
11use embassy_rp::pwm::{Config, Pwm}; 12use embassy_rp::pwm::{self, Pwm};
12use embassy_rp::relocate::RelocatedProgram; 13use embassy_rp::relocate::RelocatedProgram;
13use embassy_rp::{into_ref, Peripheral, PeripheralRef}; 14use embassy_rp::{into_ref, Peripheral, PeripheralRef};
14use embassy_time::{Duration, Instant, Timer}; 15use embassy_time::{Duration, Instant, Timer};
@@ -29,7 +30,7 @@ async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default()); 30 let p = embassy_rp::init(Default::default());
30 31
31 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { 32 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
32 let mut c = Config::default(); 33 let mut c = pwm::Config::default();
33 c.divider = 125.into(); 34 c.divider = 125.into();
34 c.top = 100; 35 c.top = 100;
35 c.compare_b = 50; 36 c.compare_b = 50;
@@ -83,7 +84,6 @@ impl<'l> HD44780<'l> {
83 ) -> HD44780<'l> { 84 ) -> HD44780<'l> {
84 into_ref!(dma); 85 into_ref!(dma);
85 86
86 let db7pin = db7.pin();
87 let Pio { 87 let Pio {
88 mut common, 88 mut common,
89 mut irq0, 89 mut irq0,
@@ -118,13 +118,17 @@ impl<'l> HD44780<'l> {
118 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); 118 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
119 119
120 let relocated = RelocatedProgram::new(&prg.program); 120 let relocated = RelocatedProgram::new(&prg.program);
121 sm0.use_program(&common.load_program(&relocated), &[&e]); 121 let mut cfg = Config::default();
122 sm0.set_clkdiv(125 * 256); 122 cfg.use_program(&common.load_program(&relocated), &[&e]);
123 sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); 123 cfg.clock_divider = 125u8.into();
124 sm0.set_out_shift_dir(ShiftDirection::Left); 124 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
125 sm0.set_fifo_join(FifoJoin::TxOnly); 125 cfg.shift_out = ShiftConfig {
126 sm0.set_autopull(true); 126 auto_fill: true,
127 sm0.set_pull_threshold(32); 127 direction: ShiftDirection::Left,
128 threshold: 32,
129 };
130 cfg.fifo_join = FifoJoin::TxOnly;
131 sm0.set_config(&cfg);
128 132
129 sm0.set_enable(true); 133 sm0.set_enable(true);
130 // init to 8 bit thrice 134 // init to 8 bit thrice
@@ -188,13 +192,15 @@ impl<'l> HD44780<'l> {
188 ); 192 );
189 193
190 let relocated = RelocatedProgram::new(&prg.program); 194 let relocated = RelocatedProgram::new(&prg.program);
191 sm0.use_program(&common.load_program(&relocated), &[&e]); 195 let mut cfg = Config::default();
192 sm0.set_clkdiv(8 * 256); // ~64ns/insn 196 cfg.use_program(&common.load_program(&relocated), &[&e]);
193 sm0.set_jmp_pin(db7pin); 197 cfg.clock_divider = 8u8.into(); // ~64ns/insn
194 sm0.set_set_pins(&[&rs, &rw]); 198 cfg.set_jmp_pin(&db7);
195 sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); 199 cfg.set_set_pins(&[&rs, &rw]);
196 sm0.set_out_shift_dir(ShiftDirection::Left); 200 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
197 sm0.set_fifo_join(FifoJoin::TxOnly); 201 cfg.shift_out.direction = ShiftDirection::Left;
202 cfg.fifo_join = FifoJoin::TxOnly;
203 sm0.set_config(&cfg);
198 204
199 sm0.set_enable(true); 205 sm0.set_enable(true);
200 206
diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs
index 889970541..d7c4742d8 100644
--- a/examples/rp/src/bin/ws2812-pio.rs
+++ b/examples/rp/src/bin/ws2812-pio.rs
@@ -3,10 +3,12 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_embedded_hal::SetConfig;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_rp::pio::{Common, FifoJoin, Instance, Pio, PioPin, ShiftDirection, StateMachine}; 8use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
8use embassy_rp::relocate::RelocatedProgram; 9use embassy_rp::relocate::RelocatedProgram;
9use embassy_time::{Duration, Timer}; 10use embassy_time::{Duration, Timer};
11use fixed_macro::fixed;
10use smart_leds::RGB8; 12use smart_leds::RGB8;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12pub struct Ws2812<'d, P: Instance, const S: usize> { 14pub struct Ws2812<'d, P: Instance, const S: usize> {
@@ -43,35 +45,30 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
43 a.bind(&mut wrap_source); 45 a.bind(&mut wrap_source);
44 46
45 let prg = a.assemble_with_wrap(wrap_source, wrap_target); 47 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
48 let mut cfg = Config::default();
46 49
47 // Pin config 50 // Pin config
48 let out_pin = pio.make_pio_pin(pin); 51 let out_pin = pio.make_pio_pin(pin);
49 52
50 let relocated = RelocatedProgram::new(&prg); 53 let relocated = RelocatedProgram::new(&prg);
51 sm.use_program(&pio.load_program(&relocated), &[&out_pin]); 54 cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
52 55
53 // Clock config 56 // Clock config, measured in kHz to avoid overflows
54 // TODO CLOCK_FREQ should come from embassy_rp 57 // TODO CLOCK_FREQ should come from embassy_rp
55 const CLOCK_FREQ: u32 = 125_000_000; 58 let clock_freq = fixed!(125_000: U24F8);
56 const WS2812_FREQ: u32 = 800_000; 59 let ws2812_freq = fixed!(800: U24F8);
57 60 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
58 let bit_freq = WS2812_FREQ * CYCLES_PER_BIT; 61 cfg.clock_divider = clock_freq / bit_freq;
59 let mut int = CLOCK_FREQ / bit_freq;
60 let rem = CLOCK_FREQ - (int * bit_freq);
61 let frac = (rem * 256) / bit_freq;
62 // 65536.0 is represented as 0 in the pio's clock divider
63 if int == 65536 {
64 int = 0;
65 }
66
67 sm.set_clkdiv((int << 8) | frac);
68 62
69 // FIFO config 63 // FIFO config
70 sm.set_autopull(true); 64 cfg.fifo_join = FifoJoin::TxOnly;
71 sm.set_fifo_join(FifoJoin::TxOnly); 65 cfg.shift_out = ShiftConfig {
72 sm.set_pull_threshold(24); 66 auto_fill: true,
73 sm.set_out_shift_dir(ShiftDirection::Left); 67 threshold: 24,
74 68 direction: ShiftDirection::Left,
69 };
70
71 sm.set_config(&cfg);
75 sm.set_enable(true); 72 sm.set_enable(true);
76 73
77 Self { sm } 74 Self { sm }