diff options
| -rw-r--r-- | embassy-rp/src/pio.rs | 438 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_async.rs | 37 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_dma.rs | 27 | ||||
| -rw-r--r-- | examples/rp/src/bin/pio_hd44780.rs | 42 | ||||
| -rw-r--r-- | examples/rp/src/bin/ws2812-pio.rs | 39 |
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 | ||
| 7 | use atomic_polyfill::{AtomicU32, AtomicU8}; | 7 | use atomic_polyfill::{AtomicU32, AtomicU8}; |
| 8 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | 8 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; |
| 9 | use embassy_embedded_hal::SetConfig; | ||
| 9 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | use fixed::types::extra::U8; | ||
| 13 | use fixed::FixedU32; | ||
| 11 | use pac::io::vals::Gpio0ctrlFuncsel; | 14 | use pac::io::vals::Gpio0ctrlFuncsel; |
| 15 | use pac::pio::vals::SmExecctrlStatusSel; | ||
| 12 | use pio::{SideSet, Wrap}; | 16 | use pio::{SideSet, Wrap}; |
| 13 | 17 | ||
| 14 | use crate::dma::{Channel, Transfer, Word}; | 18 | use crate::dma::{Channel, Transfer, Word}; |
| @@ -39,8 +43,12 @@ const NEW_AW: AtomicWaker = AtomicWaker::new(); | |||
| 39 | const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); | 43 | const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); |
| 40 | static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; | 44 | static 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)] | ||
| 42 | pub enum FifoJoin { | 49 | pub 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)] | ||
| 52 | pub enum ShiftDirection { | 62 | pub 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)] | ||
| 79 | pub enum StatusSource { | ||
| 80 | #[default] | ||
| 81 | TxFifoLevel = 0, | ||
| 82 | RxFifoLevel = 1, | ||
| 83 | } | ||
| 84 | |||
| 65 | const RXNEMPTY_MASK: u32 = 1 << 0; | 85 | const RXNEMPTY_MASK: u32 = 1 << 0; |
| 66 | const TXNFULL_MASK: u32 = 1 << 4; | 86 | const TXNFULL_MASK: u32 = 1 << 4; |
| 67 | const SMIRQ_MASK: u32 = 1 << 8; | 87 | const 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] | ||
| 503 | pub 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))] | ||
| 513 | pub 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))] | ||
| 521 | pub 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)] | ||
| 532 | pub 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 | |||
| 553 | impl<'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 | |||
| 574 | impl<'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 | |||
| 640 | impl<'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 | |||
| 480 | impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | 696 | impl<'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 | ||
| 23 | defmt = "0.3" | 23 | defmt = "0.3" |
| 24 | defmt-rtt = "0.4" | 24 | defmt-rtt = "0.4" |
| 25 | fixed = "1.23.1" | ||
| 26 | fixed-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"] } |
| 27 | cortex-m = { version = "0.7.6", features = ["inline-asm"] } | 29 | cortex-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)] |
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_embedded_hal::SetConfig; | ||
| 5 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 6 | use embassy_rp::peripherals::PIO0; | 7 | use embassy_rp::peripherals::PIO0; |
| 7 | use embassy_rp::pio::{Common, Irq, Pio, PioPin, ShiftDirection, StateMachine}; | 8 | use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | 9 | use embassy_rp::relocate::RelocatedProgram; |
| 10 | use fixed::traits::ToFixed; | ||
| 11 | use fixed_macro::types::U56F8; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 13 | ||
| 11 | fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { | 14 | fn 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)] |
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_embedded_hal::SetConfig; | ||
| 5 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 6 | use embassy_futures::join::join; | 7 | use embassy_futures::join::join; |
| 7 | use embassy_rp::pio::{Pio, ShiftDirection}; | 8 | use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | 9 | use embassy_rp::relocate::RelocatedProgram; |
| 9 | use embassy_rp::Peripheral; | 10 | use embassy_rp::Peripheral; |
| 11 | use fixed::traits::ToFixed; | ||
| 12 | use fixed_macro::types::U56F8; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 14 | ||
| 12 | fn swap_nibbles(v: u32) -> u32 { | 15 | fn 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 | ||
| 5 | use core::fmt::Write; | 5 | use core::fmt::Write; |
| 6 | 6 | ||
| 7 | use embassy_embedded_hal::SetConfig; | ||
| 7 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 8 | use embassy_rp::dma::{AnyChannel, Channel}; | 9 | use embassy_rp::dma::{AnyChannel, Channel}; |
| 9 | use embassy_rp::peripherals::PIO0; | 10 | use embassy_rp::peripherals::PIO0; |
| 10 | use embassy_rp::pio::{Direction, FifoJoin, Pio, PioPin, ShiftDirection, StateMachine}; | 11 | use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; |
| 11 | use embassy_rp::pwm::{Config, Pwm}; | 12 | use embassy_rp::pwm::{self, Pwm}; |
| 12 | use embassy_rp::relocate::RelocatedProgram; | 13 | use embassy_rp::relocate::RelocatedProgram; |
| 13 | use embassy_rp::{into_ref, Peripheral, PeripheralRef}; | 14 | use embassy_rp::{into_ref, Peripheral, PeripheralRef}; |
| 14 | use embassy_time::{Duration, Instant, Timer}; | 15 | use 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 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_embedded_hal::SetConfig; | ||
| 6 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::pio::{Common, FifoJoin, Instance, Pio, PioPin, ShiftDirection, StateMachine}; | 8 | use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; |
| 8 | use embassy_rp::relocate::RelocatedProgram; | 9 | use embassy_rp::relocate::RelocatedProgram; |
| 9 | use embassy_time::{Duration, Timer}; | 10 | use embassy_time::{Duration, Timer}; |
| 11 | use fixed_macro::fixed; | ||
| 10 | use smart_leds::RGB8; | 12 | use smart_leds::RGB8; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | pub struct Ws2812<'d, P: Instance, const S: usize> { | 14 | pub 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 } |
