mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
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:
parent
233f7c9475
commit
2eb7923ebe
|
@ -53,7 +53,7 @@ fn main() -> ! {
|
||||||
.clock_divisor(div)
|
.clock_divisor(div)
|
||||||
.build(sm0);
|
.build(sm0);
|
||||||
// The GPIO pin needs to be configured as an output.
|
// 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();
|
sm.start();
|
||||||
|
|
||||||
// PIO runs in background, independently from CPU
|
// PIO runs in background, independently from CPU
|
||||||
|
|
|
@ -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).
|
/// PIO State Machine (uninitialized, without a program).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UninitStateMachine<SM: ValidStateMachine> {
|
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
|
/// The user has to make sure that they do not select any pins that are in use by any
|
||||||
/// 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
|
|
||||||
/// other state machines of the same PIO block.
|
/// 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
|
/// The iterator's item are pairs of `(pin_number, pin_state)`.
|
||||||
/// output pins.
|
pub fn set_pins(&mut self, pins: impl IntoIterator<Item = (u8, PinState)>) {
|
||||||
pub fn set_pindirs_with_mask(&mut self, mut pins: u32, pindir: u32) {
|
let saved_ctrl = self.sm.sm().sm_pinctrl.read();
|
||||||
let mut pin = 0;
|
for (pin_num, pin_state) in pins {
|
||||||
let prev_pinctrl = self.sm.sm().sm_pinctrl.read().bits();
|
self.sm
|
||||||
// For each pin in the mask, we select the pin as a SET pin and then execute "set PINDIRS,
|
.sm()
|
||||||
// <direction>".
|
.sm_pinctrl
|
||||||
while pins != 0 {
|
.write(|w| unsafe { w.set_base().bits(pin_num).set_count().bits(1) });
|
||||||
if (pins & 1) != 0 {
|
self.set_instruction(
|
||||||
self.sm.sm().sm_pinctrl.write(|w| {
|
pio::InstructionOperands::SET {
|
||||||
unsafe {
|
destination: pio::SetDestination::PINS,
|
||||||
w.set_count().bits(1);
|
data: if PinState::High == pin_state { 1 } else { 0 },
|
||||||
w.set_base().bits(pin as u8);
|
|
||||||
}
|
}
|
||||||
w
|
.encode(),
|
||||||
});
|
);
|
||||||
let set_pindirs = pio::Instruction {
|
}
|
||||||
operands: pio::InstructionOperands::SET {
|
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,
|
destination: pio::SetDestination::PINDIRS,
|
||||||
data: ((pindir >> pin) & 0x1) as u8,
|
data: if PinDir::Output == pin_dir { 1 } else { 0 },
|
||||||
},
|
|
||||||
delay: 0,
|
|
||||||
side_set: None,
|
|
||||||
}
|
}
|
||||||
.encode(SideSet::new(false, 0, false));
|
.encode(),
|
||||||
self.sm.sm().sm_instr.write(|w| {
|
);
|
||||||
unsafe {
|
|
||||||
w.sm0_instr().bits(set_pindirs);
|
|
||||||
}
|
}
|
||||||
w
|
self.sm
|
||||||
});
|
.sm()
|
||||||
}
|
.sm_pinctrl
|
||||||
pin += 1;
|
.write(|w| unsafe { w.bits(saved_ctrl.bits()) });
|
||||||
pins >>= 1;
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue