Implements methods to allow presetting the pin state & direction (#167)

* Implements methods to allow presetting the pin state & direction

Enabling those methods allows to save a few valuable instructions
in the PIO's memory.

* Update pio_proc_blink with new set_pindirs
This commit is contained in:
Wilfried Chauveau 2021-10-22 11:13:22 +01:00 committed by GitHub
parent 233f7c9475
commit 2eb7923ebe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 46 deletions

View file

@ -53,7 +53,7 @@ fn main() -> ! {
.clock_divisor(div)
.build(sm0);
// The GPIO pin needs to be configured as an output.
sm.set_pindirs_with_mask(1 << led_pin_id, 1 << led_pin_id);
sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]);
sm.start();
// PIO runs in background, independently from CPU

View file

@ -360,6 +360,28 @@ impl<P: PIOExt, SM: StateMachineIndex> ValidStateMachine for (P, SM) {
}
}
/// Pin State in the PIO
///
/// Note the GPIO is able to override/invert that.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PinState {
/// Pin in Low state.
High,
/// Pin in Low state.
Low,
}
/// Pin direction in the PIO
///
/// Note the GPIO is able to override/invert that.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PinDir {
/// Pin set as an Input
Input,
/// Pin set as an Output.
Output,
}
/// PIO State Machine (uninitialized, without a program).
#[derive(Debug)]
pub struct UninitStateMachine<SM: ValidStateMachine> {
@ -500,56 +522,58 @@ impl<SM: ValidStateMachine> StateMachine<SM, Stopped> {
}
}
/// Sets the pin directions for the specified pins.
/// Sets the pin state for the specified pins.
///
/// The `pins` parameter specifies a set of pins as a mask, and `pindir` contains the
/// directions that are configured for these pins. The bits in both masks correspond to the pin
/// number. The user has to make sure that they do not select any pins that are in use by any
/// The user has to make sure that they do not select any pins that are in use by any
/// other state machines of the same PIO block.
///
/// This function needs to be called for sideset pins if they are supposed to be used as
/// output pins.
pub fn set_pindirs_with_mask(&mut self, mut pins: u32, pindir: u32) {
let mut pin = 0;
let prev_pinctrl = self.sm.sm().sm_pinctrl.read().bits();
// For each pin in the mask, we select the pin as a SET pin and then execute "set PINDIRS,
// <direction>".
while pins != 0 {
if (pins & 1) != 0 {
self.sm.sm().sm_pinctrl.write(|w| {
unsafe {
w.set_count().bits(1);
w.set_base().bits(pin as u8);
}
w
});
let set_pindirs = pio::Instruction {
operands: pio::InstructionOperands::SET {
destination: pio::SetDestination::PINDIRS,
data: ((pindir >> pin) & 0x1) as u8,
},
delay: 0,
side_set: None,
/// The iterator's item are pairs of `(pin_number, pin_state)`.
pub fn set_pins(&mut self, pins: impl IntoIterator<Item = (u8, PinState)>) {
let saved_ctrl = self.sm.sm().sm_pinctrl.read();
for (pin_num, pin_state) in pins {
self.sm
.sm()
.sm_pinctrl
.write(|w| unsafe { w.set_base().bits(pin_num).set_count().bits(1) });
self.set_instruction(
pio::InstructionOperands::SET {
destination: pio::SetDestination::PINS,
data: if PinState::High == pin_state { 1 } else { 0 },
}
.encode(SideSet::new(false, 0, false));
self.sm.sm().sm_instr.write(|w| {
unsafe {
w.sm0_instr().bits(set_pindirs);
}
w
});
}
pin += 1;
pins >>= 1;
.encode(),
);
}
// We modified PINCTRL, yet the program assumes a certain configuration, so restore the
// previous value.
self.sm.sm().sm_pinctrl.write(|w| {
unsafe {
w.bits(prev_pinctrl);
}
w
});
self.sm
.sm()
.sm_pinctrl
.write(|w| unsafe { w.bits(saved_ctrl.bits()) });
}
/// Set pin directions.
///
/// The user has to make sure that they do not select any pins that are in use by any
/// other state machines of the same PIO block.
///
/// The iterator's item are pairs of `(pin_number, pin_dir)`.
pub fn set_pindirs(&mut self, pindirs: impl IntoIterator<Item = (u8, PinDir)>) {
let saved_ctrl = self.sm.sm().sm_pinctrl.read();
for (pinnum, pin_dir) in pindirs {
self.sm
.sm()
.sm_pinctrl
.write(|w| unsafe { w.set_base().bits(pinnum).set_count().bits(1) });
self.set_instruction(
pio::InstructionOperands::SET {
destination: pio::SetDestination::PINDIRS,
data: if PinDir::Output == pin_dir { 1 } else { 0 },
}
.encode(),
);
}
self.sm
.sm()
.sm_pinctrl
.write(|w| unsafe { w.bits(saved_ctrl.bits()) });
}
}