aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-05-06 11:36:07 +0200
committerpennae <[email protected]>2023-05-06 17:23:41 +0200
commit8e4d65e163bd484efc4fb31d20b14e6ac4a88de7 (patch)
tree0d1623f5b7711993ee549041881601193e782984
parent2873cb93ee3111d984c35287ea9d98f1218d1024 (diff)
rp/pio: configure state machines with Config struct
the many individual sets aren't very efficient, and almost no checks were done to ensure that the configuration written to the hardware was actually valid. this adresses both of these.
-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 }