rp2040/
pio.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive 2024.
4//
5// Author: Radu Matei <radu.matei.05.21@gmail.com>
6//         Alberto Udrea <albertoudrea4@gmail.com>
7
8//! Programmable Input Output (PIO) hardware.
9//! Refer to the RP2040 Datasheet, Section 3 for more information.
10//! RP2040 Datasheet [1].
11//!
12//! [1]: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
13
14use core::cell::Cell;
15
16use kernel::utilities::cells::OptionalCell;
17use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
18use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
19use kernel::utilities::StaticRef;
20use kernel::{debug, ErrorCode};
21
22use crate::gpio::{GpioFunction, RPGpio, RPGpioPin};
23
24const NUMBER_STATE_MACHINES: usize = 4;
25const NUMBER_INSTR_MEMORY_LOCATIONS: usize = 32;
26
27#[repr(C)]
28struct InstrMem {
29    // Write-only access to instruction memory locations 0-31
30    instr_mem: ReadWrite<u32, INSTR_MEMx::Register>,
31}
32
33#[repr(C)]
34struct StateMachineReg {
35    // Clock divisor register for state machine x
36    // Frequency = clock freq / (CLKDIV_INT + CLKDIV_FRAC / 256)
37    clkdiv: ReadWrite<u32, SMx_CLKDIV::Register>,
38    // Execution/behavioural settings for state machine x
39    execctrl: ReadWrite<u32, SMx_EXECCTRL::Register>,
40    // Control behaviour of the input/output shift registers for
41    // state machine x
42    shiftctrl: ReadWrite<u32, SMx_SHIFTCTRL::Register>,
43    // Current instruction address of state machine x
44    addr: ReadOnly<u32, SMx_ADDR::Register>,
45    // Read to see the instruction currently addressed by state
46    // machine x’s program counter Write to execute an instruction
47    // immediately (including jumps) and then resume execution.
48    instr: ReadWrite<u32, SMx_INSTR::Register>,
49    // State machine pin control
50    pinctrl: ReadWrite<u32, SMx_PINCTRL::Register>,
51}
52
53register_structs! {
54PioRegisters {
55        // PIO control register
56        (0x000 => ctrl: ReadWrite<u32, CTRL::Register>),
57        // FIFO status register
58        (0x004 => fstat: ReadOnly<u32, FSTAT::Register>),
59        // FIFO debug register
60        (0x008 => fdebug: ReadWrite<u32, FDEBUG::Register>),
61        // FIFO levels
62        (0x00C => flevel: ReadOnly<u32, FLEVEL::Register>),
63        // Direct write access to the TX FIFO for this state machine. Each
64        // write pushes one word to the FIFO. Attempting to write to a full
65        // FIFO has no effect on the FIFO state or contents, and sets the
66        // sticky FDEBUG_TXOVER error flag for this FIFO.
67        (0x010 => txf: [ReadWrite<u32, TXFx::Register>; 4]),
68        // Direct read access to the RX FIFO for this state machine. Each
69        // read pops one word from the FIFO. Attempting to read from an empty
70        // FIFO has no effect on the FIFO state, and sets the sticky
71        // FDEBUG_RXUNDER error flag for this FIFO. The data returned
72        // to the system on a read from an empty FIFO is undefined.
73        (0x020 => rxf: [ReadOnly<u32, RXFx::Register>; 4]),
74        // State machine IRQ flags register. Write 1 to clear. There are 8
75        // state machine IRQ flags, which can be set, cleared, and waited on
76        // by the state machines. There’s no fixed association between
77        // flags and state machines — any state machine can use any flag.
78        // Any of the 8 flags can be used for timing synchronisation
79        // between state machines, using IRQ and WAIT instructions. The
80        // lower four of these flags are also routed out to system-level
81        // interrupt requests, alongside FIFO status interrupts —
82        // see e.g. IRQ0_INTE.
83        (0x030 => irq: ReadWrite<u32, IRQ::Register>),
84        // Writing a 1 to each of these bits will forcibly assert the
85        // corresponding IRQ. Note this is different to the INTF register:
86        // writing here affects PIO internal state. INTF just asserts the
87        // processor-facing IRQ signal for testing ISRs, and is not visible to
88        // the state machines.
89        (0x034 => irq_force: ReadWrite<u32, IRQ_FORCE::Register>),
90        // There is a 2-flipflop synchronizer on each GPIO input, which
91        // protects PIO logic from metastabilities. This increases input
92        // delay, and for fast synchronous IO (e.g. SPI) these synchronizers
93        // may need to be bypassed. Each bit in this register corresponds
94        // to one GPIO.
95        // 0 → input is synchronized (default)
96        // 1 → synchronizer is bypassed
97        // If in doubt, leave this register as all zeroes.
98        (0x038 => input_sync_bypass: ReadWrite<u32, INPUT_SYNC_BYPASS::Register>),
99        // Read to sample the pad output values PIO is currently driving
100        // to the GPIOs.
101        (0x03C => dbg_padout: ReadOnly<u32, DBG_PADOUT::Register>),
102        // Read to sample the pad output enables (direction) PIO is
103        // currently driving to the GPIOs. On RP2040 there are 30 GPIOs,
104        // so the two most significant bits are hardwired to 0.
105        (0x040 => dbg_padoe: ReadOnly<u32, DBG_PADOE::Register>),
106        // The PIO hardware has some free parameters that may vary
107        // between chip products.
108        (0x044 => dbg_cfginfo: ReadOnly<u32, DBG_CFGINFO::Register>),
109        // Write-only access to instruction memory locations 0-31
110        (0x048 => instr_mem: [InstrMem; NUMBER_INSTR_MEMORY_LOCATIONS]),
111        // State Machines
112        (0x0c8 => sm: [StateMachineReg; NUMBER_STATE_MACHINES]),
113        // Raw Interrupts
114        (0x128 => intr: ReadWrite<u32, INTR::Register>),
115        // Interrupt Enable for irq0
116        (0x12C => irq0_inte: ReadWrite<u32, IRQ0_INTE::Register>),
117        // Interrupt Force for irq0
118        (0x130 => irq0_intf: ReadWrite<u32, IRQ0_INTF::Register>),
119        // Interrupt status after masking & forcing for irq0
120        (0x134 => irq0_ints: ReadWrite<u32, IRQ0_INTS::Register>),
121        // Interrupt Enable for irq1
122        (0x138 => irq1_inte: ReadWrite<u32, IRQ1_INTE::Register>),
123        // Interrupt Force for irq1
124        (0x13C => irq1_intf: ReadWrite<u32, IRQ1_INTF::Register>),
125        // Interrupt status after masking & forcing for irq1
126        (0x140 => irq1_ints: ReadWrite<u32, IRQ1_INTS::Register>),
127        (0x144 => @END),
128    }
129}
130
131register_bitfields![u32,
132CTRL [
133    // Restart a state machine’s clock divider from an initial
134    // phase of 0. Clock dividers are free-running, so once
135    // started, their output (including fractional jitter) is
136    // completely determined by the integer/fractional divisor
137    // configured in SMx_CLKDIV. This means that, if multiple
138    // clock dividers with the same divisor are restarted
139    // simultaneously, by writing multiple 1 bits to this field, the
140    // execution clocks of those state machines will run in
141    // precise lockstep.
142    // - SM_ENABLE does not stop the clock divider from running
143    // - CLKDIV_RESTART can be written to whilst the state machine is running
144    CLKDIV3_RESTART OFFSET(11) NUMBITS(1) [],
145    CLKDIV2_RESTART OFFSET(10) NUMBITS(1) [],
146    CLKDIV1_RESTART OFFSET(9) NUMBITS(1) [],
147    CLKDIV0_RESTART OFFSET(8) NUMBITS(1) [],
148    // Write 1 to instantly clear internal SM state which may be
149    // otherwise difficult to access and will affect future
150    // execution.
151    // Specifically, the following are cleared: input and output
152    // shift counters; the contents of the input shift register; the
153    // delay counter; the waiting-on-IRQ state; any stalled
154    // instruction written to SMx_INSTR or run by OUT/MOV
155    // EXEC; any pin write left asserted due to OUT_STICKY.
156    SM3_RESTART OFFSET(7) NUMBITS(1) [],
157    SM2_RESTART OFFSET(6) NUMBITS(1) [],
158    SM1_RESTART OFFSET(5) NUMBITS(1) [],
159    SM0_RESTART OFFSET(4) NUMBITS(1) [],
160    // Enable/disable each of the four state machines by writing
161    // 1/0 to each of these four bits. When disabled, a state
162    // machine will cease executing instructions, except those
163    // written directly to SMx_INSTR by the system. Multiple bits
164    // can be set/cleared at once to run/halt multiple state
165    // machines simultaneously.
166    SM3_ENABLE OFFSET(3) NUMBITS(1) [],
167    SM2_ENABLE OFFSET(2) NUMBITS(1) [],
168    SM1_ENABLE OFFSET(1) NUMBITS(1) [],
169    SM0_ENABLE OFFSET(0) NUMBITS(1) [],
170],
171FSTAT [
172    // State machine TX FIFO is empty
173    TXEMPTY3 OFFSET(27) NUMBITS(1) [],
174    TXEMPTY2 OFFSET(26) NUMBITS(1) [],
175    TXEMPTY1 OFFSET(25) NUMBITS(1) [],
176    TXEMPTY0 OFFSET(24) NUMBITS(1) [],
177    // State machine TX FIFO is full
178    TXFULL3 OFFSET(19) NUMBITS(1) [],
179    TXFULL2 OFFSET(18) NUMBITS(1) [],
180    TXFULL1 OFFSET(17) NUMBITS(1) [],
181    TXFULL0 OFFSET(16) NUMBITS(1) [],
182    // State machine RX FIFO is empty
183    RXEMPTY3 OFFSET(11) NUMBITS(1) [],
184    RXEMPTY2 OFFSET(10) NUMBITS(1) [],
185    RXEMPTY1 OFFSET(9) NUMBITS(1) [],
186    RXEMPTY0 OFFSET(8) NUMBITS(1) [],
187    // State machine RX FIFO is full
188    RXFULL3 OFFSET(3) NUMBITS(1) [],
189    RXFULL2 OFFSET(2) NUMBITS(1) [],
190    RXFULL1 OFFSET(1) NUMBITS(1) [],
191    RXFULL0 OFFSET(0) NUMBITS(1) []
192],
193FDEBUG [
194    // State machine has stalled on empty TX FIFO during a
195    // blocking PULL, or an OUT with autopull enabled. Write 1 to
196    // clear.
197    TXSTALL OFFSET(24) NUMBITS(4) [],
198    // TX FIFO overflow (i.e. write-on-full by the system) has
199    // occurred. Write 1 to clear. Note that write-on-full does not
200    // alter the state or contents of the FIFO in any way, but the
201    // data that the system attempted to write is dropped, so if
202    // this flag is set, your software has quite likely dropped
203    // some data on the floor.
204    TXOVER OFFSET(16) NUMBITS(4) [],
205    // RX FIFO underflow (i.e. read-on-empty by the system) has
206    // occurred. Write 1 to clear. Note that read-on-empty does
207    // not perturb the state of the FIFO in any way, but the data
208    // returned by reading from an empty FIFO is undefined, so
209    // this flag generally only becomes set due to some kind of
210    // software error.
211    RXUNDER OFFSET(8) NUMBITS(4) [],
212    // State machine has stalled on full RX FIFO during a
213    // blocking PUSH, or an IN with autopush enabled. This flag
214    // is also set when a nonblocking PUSH to a full FIFO took
215    // place, in which case the state machine has dropped data.
216    // Write 1 to clear.
217    RXSTALL OFFSET(0) NUMBITS(4) []
218],
219FLEVEL [
220    RX3 OFFSET(28) NUMBITS(4) [],
221    TX3 OFFSET(24) NUMBITS(4) [],
222    RX2 OFFSET(20) NUMBITS(4) [],
223    TX2 OFFSET(16) NUMBITS(4) [],
224    RX1 OFFSET(12) NUMBITS(4) [],
225    TX1 OFFSET(8) NUMBITS(4) [],
226    RX0 OFFSET(4) NUMBITS(4) [],
227    TX0 OFFSET(0) NUMBITS(4) []
228],
229TXFx [
230    TXF OFFSET(0) NUMBITS(32) []
231],
232RXFx [
233    RXF OFFSET(0) NUMBITS(32) []
234],
235IRQ [
236    IRQ7 OFFSET(7) NUMBITS(1) [],
237    IRQ6 OFFSET(6) NUMBITS(1) [],
238    IRQ5 OFFSET(5) NUMBITS(1) [],
239    IRQ4 OFFSET(4) NUMBITS(1) [],
240    IRQ3 OFFSET(3) NUMBITS(1) [],
241    IRQ2 OFFSET(2) NUMBITS(1) [],
242    IRQ1 OFFSET(1) NUMBITS(1) [],
243    IRQ0 OFFSET(0) NUMBITS(1) []
244],
245IRQ_FORCE [
246    IRQ_FORCE OFFSET(0) NUMBITS(8) []
247],
248INPUT_SYNC_BYPASS [
249    INPUT_SYNC_BYPASS OFFSET(0) NUMBITS(32) []
250],
251DBG_PADOUT [
252    DBG_PADOUT OFFSET(0) NUMBITS(32) []
253],
254DBG_PADOE [
255    DBG_PADOE OFFSET(0) NUMBITS(32) []
256],
257DBG_CFGINFO [
258    // The size of the instruction memory, measured in units of
259    // one instruction
260    IMEM_SIZE OFFSET(16) NUMBITS(6) [],
261    // The number of state machines this PIO instance is
262    // equipped with.
263    SM_COUNT OFFSET(8) NUMBITS(4) [],
264    // The depth of the state machine TX/RX FIFOs, measured in
265    // words.
266    FIFO_DEPTH OFFSET(0) NUMBITS(6) []
267],
268INSTR_MEMx [
269    // Write-only access to instruction memory location x
270    INSTR_MEM OFFSET(0) NUMBITS(16) []
271],
272SMx_CLKDIV [
273    // Effective frequency is sysclk/(int + frac/256).
274    // Value of 0 is interpreted as 65536. If INT is 0, FRAC must
275    // also be 0.
276    INT OFFSET(16) NUMBITS(16) [],
277    // Fractional part of clock divisor
278    FRAC OFFSET(8) NUMBITS(8) []
279],
280SMx_EXECCTRL [
281    // If 1, an instruction written to SMx_INSTR is stalled, and
282    // latched by the state machine. Will clear to 0 once this
283    // instruction completes.
284    EXEC_STALLED OFFSET(31) NUMBITS(1) [],
285    // If 1, the MSB of the Delay/Side-set instruction field is used
286    // as side-set enable, rather than a side-set data bit. This
287    // allows instructions to perform side-set optionally, rather
288    // than on every instruction, but the maximum possible side-
289    // set width is reduced from 5 to 4. Note that the value of
290    // PINCTRL_SIDESET_COUNT is inclusive of this enable bit.
291    SIDE_EN OFFSET(30) NUMBITS(1) [],
292    // If 1, side-set data is asserted to pin directions, instead of
293    // pin values
294    SIDE_PINDIR OFFSET(29) NUMBITS(1) [],
295    // The GPIO number to use as condition for JMP PIN.
296    // Unaffected by input mapping.
297    JMP_PIN OFFSET(24) NUMBITS(5) [],
298    // Which data bit to use for inline OUT enable
299    OUT_EN_SEL OFFSET(19) NUMBITS(5) [],
300    // If 1, use a bit of OUT data as an auxiliary write enable
301    // When used in conjunction with OUT_STICKY, writes with
302    // an enable of 0 will
303    // deassert the latest pin write. This can create useful
304    // masking/override behaviour
305    // due to the priority ordering of state machine pin writes
306    // (SM0 < SM1 < …)
307    INLINE_OUT_EN OFFSET(18) NUMBITS(1) [],
308    // Continuously assert the most recent OUT/SET to the pins
309    OUT_STICKY OFFSET(17) NUMBITS(1) [],
310    // After reaching this address, execution is wrapped to
311    // wrap_bottom.
312    // If the instruction is a jump, and the jump condition is true,
313    // the jump takes priority.
314    WRAP_TOP OFFSET(12) NUMBITS(5) [],
315    // After reaching wrap_top, execution is wrapped to this
316    // address.
317    WRAP_BOTTOM OFFSET(7) NUMBITS(5) [],
318    STATUS_SEL OFFSET(4) NUMBITS(1) [],
319    // Comparison level for the MOV x, STATUS instruction
320    STATUS_N OFFSET(0) NUMBITS(4) []
321],
322SMx_SHIFTCTRL [
323    // When 1, RX FIFO steals the TX FIFO’s storage, and
324    // becomes twice as deep.
325    // TX FIFO is disabled as a result (always reads as both full
326    // and empty).
327    // FIFOs are flushed when this bit is changed.
328    FJOIN_RX OFFSET(31) NUMBITS(1) [],
329    // When 1, TX FIFO steals the RX FIFO’s storage, and
330    // becomes twice as deep.
331    // RX FIFO is disabled as a result (always reads as both full
332    // and empty).
333    // FIFOs are flushed when this bit is changed.
334    FJOIN_TX OFFSET(30) NUMBITS(1) [],
335    // Number of bits shifted out of OSR before autopull, or
336    // conditional pull (PULL IFEMPTY), will take place.
337    // Write 0 for value of 32.
338    PULL_THRESH OFFSET(25) NUMBITS(5) [],
339    // Number of bits shifted into ISR before autopush, or
340    // conditional push (PUSH IFFULL), will take place.
341    // Write 0 for value of 32
342    PUSH_THRESH OFFSET(20) NUMBITS(5) [],
343    OUT_SHIFTDIR OFFSET(19) NUMBITS(1) [
344        ShiftRight = 1,
345        ShiftLeft = 0
346    ],
347    IN_SHIFTDIR OFFSET(18) NUMBITS(1) [
348        ShiftRight = 1,
349        ShiftLeft = 0
350    ],
351    // Pull automatically when the output shift register is
352    // emptied, i.e. on or following an OUT instruction which
353    // causes the output shift counter to reach or exceed
354    // PULL_THRESH.
355    AUTOPULL OFFSET(17) NUMBITS(1) [],
356    // Push automatically when the input shift register is filled,
357    // i.e. on an IN instruction which causes the input shift
358    // counter to reach or exceed PUSH_THRESH.
359    AUTOPUSH OFFSET(16) NUMBITS(1) []
360],
361SMx_ADDR [
362    ADDR OFFSET(0) NUMBITS(5) []
363],
364SMx_INSTR [
365    INSTR OFFSET(0) NUMBITS(16) []
366],
367SMx_PINCTRL [
368    // The number of MSBs of the Delay/Side-set instruction
369    // field which are used for side-set. Inclusive of the enable
370    // bit, if present. Minimum of 0 (all delay bits, no side-set)
371    // and maximum of 5 (all side-set, no delay).
372    SIDESET_COUNT OFFSET(29) NUMBITS(3) [],
373    // The number of pins asserted by a SET. In the range 0 to 5
374    // inclusive.
375    SET_COUNT OFFSET(26) NUMBITS(3) [],
376    // The number of pins asserted by an OUT PINS, OUT
377    // PINDIRS or MOV PINS instruction. In the range 0 to 32
378    // inclusive.
379    OUT_COUNT OFFSET(20) NUMBITS(6) [],
380    // The pin which is mapped to the least-significant bit of a
381    // state machine’s IN data bus. Higher-numbered pins are
382    // mapped to consecutively more-significant data bits, with a
383    // modulo of 32 applied to pin number.
384    IN_BASE OFFSET(15) NUMBITS(5) [],
385    // The lowest-numbered pin that will be affected by a side-
386    // set operation. The MSBs of an instruction’s side-set/delay
387    // field (up to 5, determined by SIDESET_COUNT) are used
388    // for side-set data, with the remaining LSBs used for delay.
389    // The least-significant bit of the side-set portion is the bit
390    // written to this pin, with more-significant bits written to
391    // higher-numbered pins.
392    SIDESET_BASE OFFSET(10) NUMBITS(5) [],
393    // The lowest-numbered pin that will be affected by a SET
394    // PINS or SET PINDIRS instruction. The data written to this
395    // pin is the least-significant bit of the SET data.
396    SET_BASE OFFSET(5) NUMBITS(5) [],
397    // The lowest-numbered pin that will be affected by an OUT
398    // PINS, OUT PINDIRS or MOV PINS instruction. The data
399    // written to this pin will always be the least-significant bit of
400    // the OUT or MOV data.
401    OUT_BASE OFFSET(0) NUMBITS(5) []
402],
403INTR [
404    SM3 OFFSET(11) NUMBITS(1) [],
405    SM2 OFFSET(10) NUMBITS(1) [],
406    SM1 OFFSET(9) NUMBITS(1) [],
407    SM0 OFFSET(8) NUMBITS(1) [],
408    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
409    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
410    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
411    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
412    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
413    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
414    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
415    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
416],
417IRQ0_INTE [
418    SM3 OFFSET(11) NUMBITS(1) [],
419    SM2 OFFSET(10) NUMBITS(1) [],
420    SM1 OFFSET(9) NUMBITS(1) [],
421    SM0 OFFSET(8) NUMBITS(1) [],
422    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
423    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
424    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
425    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
426    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
427    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
428    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
429    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
430],
431IRQ0_INTF [
432    SM3 OFFSET(11) NUMBITS(1) [],
433    SM2 OFFSET(10) NUMBITS(1) [],
434    SM1 OFFSET(9) NUMBITS(1) [],
435    SM0 OFFSET(8) NUMBITS(1) [],
436    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
437    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
438    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
439    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
440    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
441    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
442    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
443    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
444],
445IRQ0_INTS [
446    SM3 OFFSET(0) NUMBITS(1) [],
447    SM2 OFFSET(0) NUMBITS(1) [],
448    SM1 OFFSET(0) NUMBITS(1) [],
449    SM0 OFFSET(0) NUMBITS(1) [],
450    SM3_TXNFULL OFFSET(0) NUMBITS(1) [],
451    SM2_TXNFULL OFFSET(0) NUMBITS(1) [],
452    SM1_TXNFULL OFFSET(0) NUMBITS(1) [],
453    SM0_TXNFULL OFFSET(0) NUMBITS(1) [],
454    SM3_RXNEMPTY OFFSET(0) NUMBITS(1) [],
455    SM2_RXNEMPTY OFFSET(0) NUMBITS(1) [],
456    SM1_RXNEMPTY OFFSET(0) NUMBITS(1) [],
457    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
458],
459IRQ1_INTE [
460    SM3 OFFSET(11) NUMBITS(1) [],
461    SM2 OFFSET(10) NUMBITS(1) [],
462    SM1 OFFSET(9) NUMBITS(1) [],
463    SM0 OFFSET(8) NUMBITS(1) [],
464    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
465    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
466    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
467    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
468    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
469    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
470    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
471    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
472],
473IRQ1_INTF [
474    SM3 OFFSET(11) NUMBITS(1) [],
475    SM2 OFFSET(10) NUMBITS(1) [],
476    SM1 OFFSET(9) NUMBITS(1) [],
477    SM0 OFFSET(8) NUMBITS(1) [],
478    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
479    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
480    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
481    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
482    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
483    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
484    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
485    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
486],
487IRQ1_INTS [
488    SM3 OFFSET(11) NUMBITS(1) [],
489    SM2 OFFSET(10) NUMBITS(1) [],
490    SM1 OFFSET(9) NUMBITS(1) [],
491    SM0 OFFSET(8) NUMBITS(1) [],
492    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
493    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
494    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
495    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
496    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
497    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
498    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
499    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
500]
501];
502
503const PIO_0_BASE_ADDRESS: usize = 0x50200000;
504const PIO_1_BASE_ADDRESS: usize = 0x50300000;
505const PIO0_BASE: StaticRef<PioRegisters> =
506    unsafe { StaticRef::new(PIO_0_BASE_ADDRESS as *const PioRegisters) };
507const PIO0_XOR_BASE: StaticRef<PioRegisters> =
508    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x1000) as *const PioRegisters) };
509const PIO0_SET_BASE: StaticRef<PioRegisters> =
510    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x2000) as *const PioRegisters) };
511const PIO0_CLEAR_BASE: StaticRef<PioRegisters> =
512    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x3000) as *const PioRegisters) };
513const PIO1_BASE: StaticRef<PioRegisters> =
514    unsafe { StaticRef::new(PIO_1_BASE_ADDRESS as *const PioRegisters) };
515const PIO1_XOR_BASE: StaticRef<PioRegisters> =
516    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x1000) as *const PioRegisters) };
517const PIO1_SET_BASE: StaticRef<PioRegisters> =
518    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x2000) as *const PioRegisters) };
519const PIO1_CLEAR_BASE: StaticRef<PioRegisters> =
520    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x3000) as *const PioRegisters) };
521
522/// Represents a relocated PIO program.
523///
524/// An [Iterator] that yields the original program except `JMP` instructions have
525/// relocated target addresses based on an origin.
526pub struct RelocatedProgram<'a, I>
527where
528    I: Iterator<Item = &'a u16>,
529{
530    iter: I,
531    origin: usize,
532}
533
534impl<'a, I> RelocatedProgram<'a, I>
535where
536    I: Iterator<Item = &'a u16>,
537{
538    fn new(iter: I, origin: usize) -> Self {
539        Self { iter, origin }
540    }
541}
542
543impl<'a, I> Iterator for RelocatedProgram<'a, I>
544where
545    I: Iterator<Item = &'a u16>,
546{
547    type Item = u16;
548
549    fn next(&mut self) -> Option<Self::Item> {
550        self.iter.next().map(|&instr| {
551            if instr & 0b1110_0000_0000_0000 == 0 {
552                // this is a JMP instruction -> add offset to address
553                let address = instr & 0b1_1111;
554                let address = address.wrapping_add(self.origin as u16) % 32;
555                instr & (!0b11111) | address
556            } else {
557                instr
558            }
559        })
560    }
561}
562
563pub struct LoadedProgram {
564    used_memory: u32,
565    origin: usize,
566}
567
568#[derive(Clone, Copy, PartialEq, Eq, Debug)]
569pub enum ProgramError {
570    /// Insufficient consecutive free instruction space to load program.
571    InsufficientSpace,
572    /// Loading a program would overwrite the existing one
573    AddrInUse(usize),
574}
575
576/// There are a total of 4 State Machines per PIO.
577#[derive(Clone, Copy, PartialEq, Debug)]
578pub enum SMNumber {
579    SM0 = 0,
580    SM1 = 1,
581    SM2 = 2,
582    SM3 = 3,
583}
584
585/// Array of all SMNumbers, used for convenience in Pio constructor
586const SM_NUMBERS: [SMNumber; 4] = [SMNumber::SM0, SMNumber::SM1, SMNumber::SM2, SMNumber::SM3];
587
588/// There can be 2 PIOs per RP2040.
589#[derive(PartialEq)]
590pub enum PIONumber {
591    PIO0 = 0,
592    PIO1 = 1,
593}
594
595/// The FIFO queues can be joined together for twice the length in one direction.
596#[derive(PartialEq)]
597pub enum PioFifoJoin {
598    PioFifoJoinNone = 0,
599    PioFifoJoinTx = 1,
600    PioFifoJoinRx = 2,
601}
602
603/// PIO interrupt source numbers for PIO related interrupts
604#[derive(PartialEq)]
605pub enum InterruptSources {
606    Interrupt0 = 0,
607    Interrupt1 = 1,
608    Interrupt2 = 2,
609    Interrupt3 = 3,
610    Sm0TXNotFull = 4,
611    Sm1TXNotFull = 5,
612    Sm2TXNotFull = 6,
613    Sm3TXNotFull = 7,
614    Sm0RXNotEmpty = 8,
615    Sm1RXNotEmpty = 9,
616    Sm2RXNotEmpty = 10,
617    Sm3RXNotEmpty = 11,
618}
619
620pub trait PioTxClient {
621    fn on_buffer_space_available(&self);
622}
623
624pub trait PioRxClient {
625    fn on_data_received(&self, data: u32);
626}
627
628#[derive(Clone, Copy, Debug, Default)]
629enum StateMachineState {
630    #[default]
631    Ready,
632    Waiting,
633}
634
635pub struct StateMachine {
636    sm_number: SMNumber,
637    registers: StaticRef<PioRegisters>,
638    xor_registers: StaticRef<PioRegisters>,
639    set_registers: StaticRef<PioRegisters>,
640    tx_state: Cell<StateMachineState>,
641    tx_client: OptionalCell<&'static dyn PioTxClient>,
642    rx_state: Cell<StateMachineState>,
643    rx_client: OptionalCell<&'static dyn PioRxClient>,
644}
645
646impl StateMachine {
647    fn new(
648        sm_id: SMNumber,
649        registers: StaticRef<PioRegisters>,
650        xor_registers: StaticRef<PioRegisters>,
651        set_registers: StaticRef<PioRegisters>,
652    ) -> StateMachine {
653        StateMachine {
654            sm_number: sm_id,
655            registers,
656            xor_registers,
657            set_registers,
658            tx_state: Cell::new(StateMachineState::Ready),
659            tx_client: OptionalCell::empty(),
660            rx_state: Cell::new(StateMachineState::Ready),
661            rx_client: OptionalCell::empty(),
662        }
663    }
664
665    /// State machine configuration with any config structure.
666    pub fn config(&self, config: &StateMachineConfiguration) {
667        self.set_in_pins(config.in_pins_base);
668        self.set_out_pins(config.out_pins_base, config.out_pins_count);
669        self.set_set_pins(config.set_pins_base, config.set_pins_count);
670        self.set_side_set_pins(
671            config.side_set_base,
672            config.side_set_bit_count,
673            config.side_set_opt_enable,
674            config.side_set_pindirs,
675        );
676        self.set_in_shift(
677            config.in_shift_direction_right,
678            config.in_autopush,
679            config.in_push_threshold,
680        );
681        self.set_out_shift(
682            config.out_shift_direction_right,
683            config.out_autopull,
684            config.out_pull_threshold,
685        );
686        self.set_jmp_pin(config.jmp_pin);
687        self.set_wrap(config.wrap_to, config.wrap);
688        self.set_mov_status(config.mov_status_sel, config.mov_status_n);
689        self.set_out_special(
690            config.out_special_sticky,
691            config.out_special_has_enable_pin,
692            config.out_special_enable_pin_index,
693        );
694        self.set_clkdiv_int_frac(config.div_int, config.div_frac);
695    }
696
697    /// Set tx client for a state machine.
698    pub fn set_tx_client(&self, client: &'static dyn PioTxClient) {
699        self.tx_client.set(client);
700    }
701
702    /// Set rx client for a state machine.
703    pub fn set_rx_client(&self, client: &'static dyn PioRxClient) {
704        self.rx_client.set(client);
705    }
706
707    /// Set every config for the IN pins.
708    ///
709    /// in_base => the starting location for the input pins
710    pub fn set_in_pins(&self, in_base: u32) {
711        self.registers.sm[self.sm_number as usize]
712            .pinctrl
713            .modify(SMx_PINCTRL::IN_BASE.val(in_base));
714    }
715
716    /// Set every config for the SET pins.
717    ///
718    /// set_base => the starting location for the SET pins
719    /// set_count => the number of SET pins
720    pub fn set_set_pins(&self, set_base: u32, set_count: u32) {
721        self.registers.sm[self.sm_number as usize]
722            .pinctrl
723            .modify(SMx_PINCTRL::SET_BASE.val(set_base));
724        self.registers.sm[self.sm_number as usize]
725            .pinctrl
726            .modify(SMx_PINCTRL::SET_COUNT.val(set_count));
727    }
728
729    /// Set every config for the OUT pins.
730    ///
731    /// out_base => the starting location for the OUT pins
732    /// out_count => the number of OUT pins
733    pub fn set_out_pins(&self, out_base: u32, out_count: u32) {
734        self.registers.sm[self.sm_number as usize]
735            .pinctrl
736            .modify(SMx_PINCTRL::OUT_BASE.val(out_base));
737        self.registers.sm[self.sm_number as usize]
738            .pinctrl
739            .modify(SMx_PINCTRL::OUT_COUNT.val(out_count));
740    }
741
742    /// Setup 'in' shifting parameters.
743    ///
744    ///  shift_right => true to shift ISR to right or false to shift to left
745    ///  autopush => true to enable, false to disable
746    ///  push_threshold => threshold in bits to shift in before auto/conditional re-pushing of the ISR
747    pub fn set_in_shift(&self, shift_right: bool, autopush: bool, push_threshold: u32) {
748        self.registers.sm[self.sm_number as usize]
749            .shiftctrl
750            .modify(SMx_SHIFTCTRL::IN_SHIFTDIR.val(shift_right.into()));
751        self.registers.sm[self.sm_number as usize]
752            .shiftctrl
753            .modify(SMx_SHIFTCTRL::AUTOPUSH.val(autopush.into()));
754        self.registers.sm[self.sm_number as usize]
755            .shiftctrl
756            .modify(SMx_SHIFTCTRL::PUSH_THRESH.val(push_threshold));
757    }
758
759    /// Setup 'out' shifting parameters.
760    ///
761    /// shift_right => `true` to shift OSR to right or false to shift to left
762    /// autopull => true to enable, false to disable
763    /// pull_threshold => threshold in bits to shift out before auto/conditional re-pulling of the OSR
764    pub fn set_out_shift(&self, shift_right: bool, autopull: bool, pull_threshold: u32) {
765        self.registers.sm[self.sm_number as usize]
766            .shiftctrl
767            .modify(SMx_SHIFTCTRL::OUT_SHIFTDIR.val(shift_right.into()));
768        self.registers.sm[self.sm_number as usize]
769            .shiftctrl
770            .modify(SMx_SHIFTCTRL::AUTOPULL.val(autopull.into()));
771        self.registers.sm[self.sm_number as usize]
772            .shiftctrl
773            .modify(SMx_SHIFTCTRL::PULL_THRESH.val(pull_threshold));
774    }
775
776    /// Set special OUT operations in a state machine.
777    ///
778    /// sticky
779    /// => true to enable sticky output (rere-asserting most recent OUT/SET pin values on subsequent cycles)
780    /// => false to disable sticky output
781    /// has_enable_pin
782    /// => true to enable auxiliary OUT enable pin
783    /// => false to disable auxiliary OUT enable pin
784    /// enable_pin_index => pin index for auxiliary OUT enable
785    pub fn set_out_special(&self, sticky: bool, has_enable_pin: bool, enable_pin_index: u32) {
786        self.registers.sm[self.sm_number as usize]
787            .execctrl
788            .modify(SMx_EXECCTRL::OUT_STICKY.val(sticky as u32));
789        self.registers.sm[self.sm_number as usize]
790            .execctrl
791            .modify(SMx_EXECCTRL::INLINE_OUT_EN.val(has_enable_pin as u32));
792        self.registers.sm[self.sm_number as usize]
793            .execctrl
794            .modify(SMx_EXECCTRL::OUT_EN_SEL.val(enable_pin_index));
795    }
796
797    /// Set the 'jmp' pin.
798    ///
799    /// pin => the raw GPIO pin number to use as the source for a jmp pin instruction
800    pub fn set_jmp_pin(&self, pin: u32) {
801        self.registers.sm[self.sm_number as usize]
802            .execctrl
803            .modify(SMx_EXECCTRL::JMP_PIN.val(pin));
804    }
805
806    /// Set the clock divider for a state machine.
807    ///
808    /// div_int => Integer part of the divisor
809    /// div_frac => Fractional part in 1/256ths
810    pub fn set_clkdiv_int_frac(&self, div_int: u32, div_frac: u32) {
811        self.registers.sm[self.sm_number as usize]
812            .clkdiv
813            .modify(SMx_CLKDIV::INT.val(div_int));
814        self.registers.sm[self.sm_number as usize]
815            .clkdiv
816            .modify(SMx_CLKDIV::FRAC.val(div_frac));
817    }
818
819    /// Setup the FIFO joining in a state machine.
820    ///
821    /// fifo_join => specifies the join type - see the `PioFifoJoin` type
822    pub fn set_fifo_join(&self, fifo_join: PioFifoJoin) {
823        if fifo_join == PioFifoJoin::PioFifoJoinRx {
824            self.registers.sm[self.sm_number as usize]
825                .shiftctrl
826                .modify(SMx_SHIFTCTRL::FJOIN_RX.val(fifo_join as u32));
827        } else if fifo_join == PioFifoJoin::PioFifoJoinTx {
828            self.registers.sm[self.sm_number as usize]
829                .shiftctrl
830                .modify(SMx_SHIFTCTRL::FJOIN_TX.val(fifo_join as u32));
831        }
832    }
833
834    /// Set every config for the SIDESET pins.
835    ///
836    /// sideset_base => the starting location for the SIDESET pins
837    /// bit_count => number of SIDESET bits per instruction - max 5
838    /// optional
839    /// => true to use the topmost sideset bit as a flag for whether to apply side set on that instruction
840    /// => false to use sideset with every instruction
841    /// pindirs
842    /// => true to affect pin direction
843    /// => false to affect value of a pin
844    pub fn set_side_set_pins(
845        &self,
846        sideset_base: u32,
847        bit_count: u32,
848        optional: bool,
849        pindirs: bool,
850    ) {
851        self.registers.sm[self.sm_number as usize]
852            .pinctrl
853            .modify(SMx_PINCTRL::SIDESET_BASE.val(sideset_base));
854        self.registers.sm[self.sm_number as usize]
855            .pinctrl
856            .modify(SMx_PINCTRL::SIDESET_COUNT.val(bit_count));
857        self.registers.sm[self.sm_number as usize]
858            .execctrl
859            .modify(SMx_EXECCTRL::SIDE_EN.val(optional as u32));
860        self.registers.sm[self.sm_number as usize]
861            .execctrl
862            .modify(SMx_EXECCTRL::SIDE_PINDIR.val(pindirs as u32));
863    }
864
865    /// Use a state machine to set the same pin direction for multiple consecutive pins for the PIO instance.
866    /// This is the pio_sm_set_consecutive_pindirs function from the pico sdk, renamed to be more clear.
867    ///
868    /// pin => starting pin
869    /// count => how many pins (including the base) should be changed
870    /// is_out
871    /// => true to set the pin as OUT
872    /// => false to set the pin as IN
873    pub fn set_pins_dirs(&self, mut pin: u32, mut count: u32, is_out: bool) {
874        // "set pindirs, 0" command created by pioasm
875        let set_pindirs_0: u16 = 0b1110000010000000;
876        self.with_paused(|| {
877            let mut pindir_val: u8 = 0x00;
878            if is_out {
879                pindir_val = 0x1f;
880            }
881            while count > 5 {
882                self.registers.sm[self.sm_number as usize]
883                    .pinctrl
884                    .modify(SMx_PINCTRL::SET_COUNT.val(5));
885                self.registers.sm[self.sm_number as usize]
886                    .pinctrl
887                    .modify(SMx_PINCTRL::SET_BASE.val(pin));
888                self.exec((set_pindirs_0) | (pindir_val as u16));
889                count -= 5;
890                pin = (pin + 5) & 0x1f;
891            }
892            self.registers.sm[self.sm_number as usize]
893                .pinctrl
894                .modify(SMx_PINCTRL::SET_COUNT.val(count));
895            self.registers.sm[self.sm_number as usize]
896                .pinctrl
897                .modify(SMx_PINCTRL::SET_BASE.val(pin));
898            self.exec((set_pindirs_0) | (pindir_val as u16));
899        });
900    }
901
902    /// Sets pin output values. Pauses the state machine to run `SET` commands
903    /// and temporarily unsets the `OUT_STICKY` bit to avoid side effects.
904    ///
905    /// pins => pins to set the value for
906    /// high => true to set the pin high
907    pub fn set_pins(&self, pins: &[&RPGpioPin<'_>], high: bool) {
908        self.with_paused(|| {
909            for pin in pins {
910                self.registers.sm[self.sm_number as usize]
911                    .pinctrl
912                    .modify(SMx_PINCTRL::SET_BASE.val(pin.pin() as u32));
913                self.registers.sm[self.sm_number as usize]
914                    .pinctrl
915                    .modify(SMx_PINCTRL::SET_COUNT.val(1));
916
917                self.exec(0b11100_000_000_00000 | high as u16);
918            }
919        });
920    }
921
922    /// Set the wrap addresses for a state machine.
923    ///
924    /// wrap_target => the instruction memory address to wrap to
925    /// wrap => the instruction memory address after which the program counters wraps to the target
926    pub fn set_wrap(&self, wrap_target: u32, wrap: u32) {
927        self.registers.sm[self.sm_number as usize]
928            .execctrl
929            .modify(SMx_EXECCTRL::WRAP_BOTTOM.val(wrap_target));
930        self.registers.sm[self.sm_number as usize]
931            .execctrl
932            .modify(SMx_EXECCTRL::WRAP_TOP.val(wrap));
933    }
934
935    /// Resets the state machine to a consistent state and configures it.
936    pub fn init(&self) {
937        self.clear_fifos();
938        self.restart();
939        self.clkdiv_restart();
940        self.registers.sm[self.sm_number as usize]
941            .instr
942            .modify(SMx_INSTR::INSTR.val(0));
943    }
944
945    /// Restart a state machine.
946    pub fn restart(&self) {
947        match self.sm_number {
948            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::SM0_RESTART::SET),
949            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::SM1_RESTART::SET),
950            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::SM2_RESTART::SET),
951            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::SM3_RESTART::SET),
952        }
953    }
954
955    /// Clear a state machine’s TX and RX FIFOs.
956    pub fn clear_fifos(&self) {
957        self.xor_registers.sm[self.sm_number as usize]
958            .shiftctrl
959            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
960        self.xor_registers.sm[self.sm_number as usize]
961            .shiftctrl
962            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
963    }
964
965    /// Restart a state machine's clock divider.
966    pub fn clkdiv_restart(&self) {
967        match self.sm_number {
968            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::CLKDIV0_RESTART::SET),
969            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::CLKDIV1_RESTART::SET),
970            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::CLKDIV2_RESTART::SET),
971            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::CLKDIV3_RESTART::SET),
972        }
973    }
974
975    /// Returns true if the TX FIFO is full.
976    pub fn tx_full(&self) -> bool {
977        let field = match self.sm_number {
978            SMNumber::SM0 => FSTAT::TXFULL0,
979            SMNumber::SM1 => FSTAT::TXFULL1,
980            SMNumber::SM2 => FSTAT::TXFULL2,
981            SMNumber::SM3 => FSTAT::TXFULL3,
982        };
983        self.registers.fstat.read(field) != 0
984    }
985
986    /// Returns true if the RX FIFO is empty.
987    pub fn rx_empty(&self) -> bool {
988        let field = match self.sm_number {
989            SMNumber::SM0 => FSTAT::RXEMPTY0,
990            SMNumber::SM1 => FSTAT::RXEMPTY1,
991            SMNumber::SM2 => FSTAT::RXEMPTY2,
992            SMNumber::SM3 => FSTAT::RXEMPTY3,
993        };
994        self.registers.fstat.read(field) != 0
995    }
996
997    /// Immediately execute an instruction on a state machine.
998    ///
999    /// => instr: the instruction to execute
1000    /// Implicitly restricted size of instr to u16, cause it's the size pio asm instr
1001    pub fn exec(&self, instr: u16) {
1002        self.registers.sm[self.sm_number as usize]
1003            .instr
1004            .modify(SMx_INSTR::INSTR.val(instr as u32));
1005    }
1006
1007    /// Executes a program on a state machine.
1008    /// Jumps to the instruction at given address and runs the program.
1009    ///
1010    /// => program: a program loaded to PIO
1011    /// => wrap: true to wrap the program, so it runs in loop
1012    pub fn exec_program(&self, program: LoadedProgram, wrap: bool) {
1013        if wrap {
1014            self.set_wrap(
1015                program.origin as u32,
1016                program.origin as u32 + program.used_memory.count_ones(),
1017            );
1018        }
1019        self.exec((program.origin as u16) & 0x1fu16)
1020    }
1021
1022    /// Set source for 'mov status' in a state machine.
1023    ///
1024    /// status_sel => comparison used for the `MOV x, STATUS` instruction
1025    /// status_n => comparison level for the `MOV x, STATUS` instruction
1026    pub fn set_mov_status(&self, status_sel: PioMovStatusType, status_n: u32) {
1027        self.registers.sm[self.sm_number as usize]
1028            .execctrl
1029            .modify(SMx_EXECCTRL::STATUS_SEL.val(status_sel as u32));
1030        self.registers.sm[self.sm_number as usize]
1031            .execctrl
1032            .modify(SMx_EXECCTRL::STATUS_N.val(status_n));
1033    }
1034
1035    /// Set a state machine's state to enabled or to disabled.
1036    ///
1037    /// enabled => true to enable the state machine
1038    pub fn set_enabled(&self, enabled: bool) {
1039        match self.sm_number {
1040            SMNumber::SM0 => self.registers.ctrl.modify(match enabled {
1041                true => CTRL::SM0_ENABLE::SET,
1042                false => CTRL::SM0_ENABLE::CLEAR,
1043            }),
1044            SMNumber::SM1 => self.registers.ctrl.modify(match enabled {
1045                true => CTRL::SM1_ENABLE::SET,
1046                false => CTRL::SM1_ENABLE::CLEAR,
1047            }),
1048            SMNumber::SM2 => self.registers.ctrl.modify(match enabled {
1049                true => CTRL::SM2_ENABLE::SET,
1050                false => CTRL::SM2_ENABLE::CLEAR,
1051            }),
1052            SMNumber::SM3 => self.registers.ctrl.modify(match enabled {
1053                true => CTRL::SM3_ENABLE::SET,
1054                false => CTRL::SM3_ENABLE::CLEAR,
1055            }),
1056        }
1057    }
1058
1059    /// Is state machine enabled.
1060    pub fn is_enabled(&self) -> bool {
1061        let field = match self.sm_number {
1062            SMNumber::SM0 => CTRL::SM0_ENABLE,
1063            SMNumber::SM1 => CTRL::SM1_ENABLE,
1064            SMNumber::SM2 => CTRL::SM2_ENABLE,
1065            SMNumber::SM3 => CTRL::SM3_ENABLE,
1066        };
1067        self.registers.ctrl.read(field) != 0
1068    }
1069
1070    /// Runs function with the state machine paused.
1071    /// Keeps pinctrl and execctrl of the SM the same during execution
1072    fn with_paused(&self, f: impl FnOnce()) {
1073        let enabled = self.is_enabled();
1074        self.set_enabled(false);
1075
1076        let pio_sm = &self.registers.sm[self.sm_number as usize];
1077
1078        let pinctrl = pio_sm.pinctrl.get();
1079        let execctrl = pio_sm.execctrl.get();
1080        // Hold pins value set by latest OUT/SET op
1081        pio_sm.execctrl.modify(SMx_EXECCTRL::OUT_STICKY::CLEAR);
1082
1083        f();
1084
1085        pio_sm.pinctrl.set(pinctrl);
1086        pio_sm.execctrl.set(execctrl);
1087        self.set_enabled(enabled);
1088    }
1089
1090    /// Write a word of data to a state machine’s TX FIFO.
1091    /// If the FIFO is full, the client will be notified when space is available.
1092    ///
1093    /// => data: the data to write to the FIFO
1094    pub fn push(&self, data: u32) -> Result<(), ErrorCode> {
1095        match self.tx_state.get() {
1096            StateMachineState::Ready => {
1097                if self.tx_full() {
1098                    // TX queue is full, set interrupt
1099                    let field = match self.sm_number {
1100                        SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::SET,
1101                        SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::SET,
1102                        SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::SET,
1103                        SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::SET,
1104                    };
1105                    self.registers.irq0_inte.modify(field);
1106                    self.tx_state.set(StateMachineState::Waiting);
1107                    Err(ErrorCode::BUSY)
1108                } else {
1109                    self.registers.txf[self.sm_number as usize].set(data);
1110                    Ok(())
1111                }
1112            }
1113            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1114        }
1115    }
1116
1117    /// Wait until a state machine's TX FIFO is empty, then write a word of data to it.
1118    /// If state machine is disabled and there is no space, an error will be returned.
1119    /// If SM is stalled on RX or in loop, this will block forever.
1120    ///
1121    /// => data: the data to write to the FIFO
1122    pub fn push_blocking(&self, data: u32) -> Result<(), ErrorCode> {
1123        if self.tx_full() && !self.is_enabled() {
1124            return Err(ErrorCode::OFF);
1125        }
1126        while self.tx_full() {}
1127        self.registers.txf[self.sm_number as usize].set(data);
1128        Ok(())
1129    }
1130
1131    /// Read a word of data from a state machine’s RX FIFO.
1132    /// If the FIFO is empty, the client will be notified when data is available.
1133    pub fn pull(&self) -> Result<u32, ErrorCode> {
1134        match self.rx_state.get() {
1135            StateMachineState::Ready => {
1136                if self.rx_empty() {
1137                    // RX queue is empty, set interrupt
1138                    let field = match self.sm_number {
1139                        SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::SET,
1140                        SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::SET,
1141                        SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::SET,
1142                        SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::SET,
1143                    };
1144                    self.registers.irq0_inte.modify(field);
1145                    self.rx_state.set(StateMachineState::Waiting);
1146                    Err(ErrorCode::BUSY)
1147                } else {
1148                    Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1149                }
1150            }
1151            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1152        }
1153    }
1154
1155    /// Reads a word of data from a state machine’s RX FIFO.
1156    /// If state machine is disabled and there is no space, an error will be returned.
1157    /// If SM is stalled on TX or in loop, this will block forever.
1158    pub fn pull_blocking(&self) -> Result<u32, ErrorCode> {
1159        if self.tx_full() && !self.is_enabled() {
1160            return Err(ErrorCode::OFF);
1161        }
1162        while self.rx_empty() {}
1163        Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1164    }
1165
1166    /// Handle a TX interrupt - notify that buffer space is available.
1167    fn handle_tx_interrupt(&self) {
1168        match self.tx_state.get() {
1169            StateMachineState::Waiting => {
1170                // TX queue has emptied, clear interrupt
1171                let field = match self.sm_number {
1172                    SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::CLEAR,
1173                    SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::CLEAR,
1174                    SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::CLEAR,
1175                    SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::CLEAR,
1176                };
1177                self.registers.irq0_inte.modify(field);
1178                self.tx_state.set(StateMachineState::Ready);
1179                self.tx_client.map(|client| {
1180                    client.on_buffer_space_available();
1181                });
1182            }
1183            StateMachineState::Ready => {}
1184        }
1185    }
1186
1187    /// Handle an RX interrupt - notify that data has been received.
1188    fn handle_rx_interrupt(&self) {
1189        match self.rx_state.get() {
1190            StateMachineState::Waiting => {
1191                // RX queue has data, clear interrupt
1192                let field = match self.sm_number {
1193                    SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::CLEAR,
1194                    SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::CLEAR,
1195                    SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::CLEAR,
1196                    SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::CLEAR,
1197                };
1198                self.registers.irq0_inte.modify(field);
1199                self.rx_state.set(StateMachineState::Ready);
1200                self.rx_client.map(|client| {
1201                    client.on_data_received(
1202                        self.registers.rxf[self.sm_number as usize].read(RXFx::RXF),
1203                    );
1204                });
1205            }
1206            StateMachineState::Ready => {}
1207        }
1208    }
1209}
1210
1211pub struct Pio {
1212    registers: StaticRef<PioRegisters>,
1213    pio_number: PIONumber,
1214    sms: [StateMachine; NUMBER_STATE_MACHINES],
1215    instructions_used: Cell<u32>,
1216    _clear_registers: StaticRef<PioRegisters>,
1217}
1218
1219/// 'MOV STATUS' types.
1220#[derive(Clone, Copy)]
1221pub enum PioMovStatusType {
1222    StatusTxLessthan = 0,
1223    StatusRxLessthan = 1,
1224}
1225
1226/// PIO State Machine configuration structure
1227///
1228/// Used to initialize a PIO with all of its state machines.
1229pub struct StateMachineConfiguration {
1230    pub out_pins_count: u32,
1231    pub out_pins_base: u32,
1232    pub set_pins_count: u32,
1233    pub set_pins_base: u32,
1234    pub in_pins_base: u32,
1235    pub side_set_base: u32,
1236    pub side_set_opt_enable: bool,
1237    pub side_set_bit_count: u32,
1238    pub side_set_pindirs: bool,
1239    pub wrap: u32,
1240    pub wrap_to: u32,
1241    pub in_shift_direction_right: bool,
1242    pub in_autopush: bool,
1243    pub in_push_threshold: u32,
1244    pub out_shift_direction_right: bool,
1245    pub out_autopull: bool,
1246    pub out_pull_threshold: u32,
1247    pub jmp_pin: u32,
1248    pub out_special_sticky: bool,
1249    pub out_special_has_enable_pin: bool,
1250    pub out_special_enable_pin_index: u32,
1251    pub mov_status_sel: PioMovStatusType,
1252    pub mov_status_n: u32,
1253    pub div_int: u32,
1254    pub div_frac: u32,
1255}
1256
1257impl Default for StateMachineConfiguration {
1258    fn default() -> Self {
1259        StateMachineConfiguration {
1260            out_pins_count: 32,
1261            out_pins_base: 0,
1262            set_pins_count: 0,
1263            set_pins_base: 0,
1264            in_pins_base: 0,
1265            side_set_base: 0,
1266            side_set_opt_enable: false,
1267            side_set_bit_count: 0,
1268            side_set_pindirs: false,
1269            wrap: 31,
1270            wrap_to: 0,
1271            in_shift_direction_right: true,
1272            in_autopush: false,
1273            in_push_threshold: 32,
1274            out_shift_direction_right: true,
1275            out_autopull: false,
1276            out_pull_threshold: 32,
1277            jmp_pin: 0,
1278            out_special_sticky: false,
1279            out_special_has_enable_pin: false,
1280            out_special_enable_pin_index: 0,
1281            mov_status_sel: PioMovStatusType::StatusTxLessthan,
1282            mov_status_n: 0,
1283            div_int: 0,
1284            div_frac: 0,
1285        }
1286    }
1287}
1288
1289impl Pio {
1290    /// Setup the function select for a GPIO to use output from the given PIO instance.
1291    pub fn gpio_init(&self, pin: &RPGpioPin) {
1292        if self.pio_number == PIONumber::PIO1 {
1293            pin.set_function(GpioFunction::PIO1)
1294        } else {
1295            pin.set_function(GpioFunction::PIO0)
1296        }
1297    }
1298
1299    /// Create a new PIO0 struct.
1300    pub fn new_pio0() -> Self {
1301        Self {
1302            registers: PIO0_BASE,
1303            _clear_registers: PIO0_CLEAR_BASE,
1304            pio_number: PIONumber::PIO0,
1305            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO0_BASE, PIO0_XOR_BASE, PIO0_SET_BASE)),
1306            instructions_used: Cell::new(0),
1307        }
1308    }
1309
1310    /// Create a new PIO1 struct.
1311    pub fn new_pio1() -> Self {
1312        Self {
1313            registers: PIO1_BASE,
1314            _clear_registers: PIO1_CLEAR_BASE,
1315            pio_number: PIONumber::PIO1,
1316            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO1_BASE, PIO1_XOR_BASE, PIO1_SET_BASE)),
1317            instructions_used: Cell::new(0),
1318        }
1319    }
1320
1321    /// Get state machine
1322    pub fn sm(&self, sm_number: SMNumber) -> &StateMachine {
1323        &self.sms[sm_number as usize]
1324    }
1325
1326    /// Enable/Disable a single source on a PIO's IRQ index.
1327    pub fn set_irq_source(
1328        &self,
1329        irq_index: u32,
1330        interrupt_source: InterruptSources,
1331        enabled: bool,
1332    ) {
1333        if irq_index == 0 {
1334            match interrupt_source {
1335                InterruptSources::Interrupt0 => self
1336                    .registers
1337                    .irq0_inte
1338                    .modify(IRQ0_INTE::SM0.val(enabled as u32)),
1339                InterruptSources::Interrupt1 => self
1340                    .registers
1341                    .irq0_inte
1342                    .modify(IRQ0_INTE::SM1.val(enabled as u32)),
1343                InterruptSources::Interrupt2 => self
1344                    .registers
1345                    .irq0_inte
1346                    .modify(IRQ0_INTE::SM2.val(enabled as u32)),
1347                InterruptSources::Interrupt3 => self
1348                    .registers
1349                    .irq0_inte
1350                    .modify(IRQ0_INTE::SM3.val(enabled as u32)),
1351                InterruptSources::Sm0TXNotFull => self
1352                    .registers
1353                    .irq0_inte
1354                    .modify(IRQ0_INTE::SM0_TXNFULL.val(enabled as u32)),
1355                InterruptSources::Sm1TXNotFull => self
1356                    .registers
1357                    .irq0_inte
1358                    .modify(IRQ0_INTE::SM1_TXNFULL.val(enabled as u32)),
1359                InterruptSources::Sm2TXNotFull => self
1360                    .registers
1361                    .irq0_inte
1362                    .modify(IRQ0_INTE::SM2_TXNFULL.val(enabled as u32)),
1363                InterruptSources::Sm3TXNotFull => self
1364                    .registers
1365                    .irq0_inte
1366                    .modify(IRQ0_INTE::SM3_TXNFULL.val(enabled as u32)),
1367                InterruptSources::Sm0RXNotEmpty => self
1368                    .registers
1369                    .irq0_inte
1370                    .modify(IRQ0_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1371                InterruptSources::Sm1RXNotEmpty => self
1372                    .registers
1373                    .irq0_inte
1374                    .modify(IRQ0_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1375                InterruptSources::Sm2RXNotEmpty => self
1376                    .registers
1377                    .irq0_inte
1378                    .modify(IRQ0_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1379                InterruptSources::Sm3RXNotEmpty => self
1380                    .registers
1381                    .irq0_inte
1382                    .modify(IRQ0_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1383            }
1384        } else if irq_index == 1 {
1385            match interrupt_source {
1386                InterruptSources::Interrupt0 => self
1387                    .registers
1388                    .irq1_inte
1389                    .modify(IRQ1_INTE::SM0.val(enabled as u32)),
1390                InterruptSources::Interrupt1 => self
1391                    .registers
1392                    .irq1_inte
1393                    .modify(IRQ1_INTE::SM1.val(enabled as u32)),
1394                InterruptSources::Interrupt2 => self
1395                    .registers
1396                    .irq1_inte
1397                    .modify(IRQ1_INTE::SM2.val(enabled as u32)),
1398                InterruptSources::Interrupt3 => self
1399                    .registers
1400                    .irq1_inte
1401                    .modify(IRQ1_INTE::SM3.val(enabled as u32)),
1402                InterruptSources::Sm0TXNotFull => self
1403                    .registers
1404                    .irq1_inte
1405                    .modify(IRQ1_INTE::SM0_TXNFULL.val(enabled as u32)),
1406                InterruptSources::Sm1TXNotFull => self
1407                    .registers
1408                    .irq1_inte
1409                    .modify(IRQ1_INTE::SM1_TXNFULL.val(enabled as u32)),
1410                InterruptSources::Sm2TXNotFull => self
1411                    .registers
1412                    .irq1_inte
1413                    .modify(IRQ1_INTE::SM2_TXNFULL.val(enabled as u32)),
1414                InterruptSources::Sm3TXNotFull => self
1415                    .registers
1416                    .irq1_inte
1417                    .modify(IRQ1_INTE::SM3_TXNFULL.val(enabled as u32)),
1418                InterruptSources::Sm0RXNotEmpty => self
1419                    .registers
1420                    .irq1_inte
1421                    .modify(IRQ1_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1422                InterruptSources::Sm1RXNotEmpty => self
1423                    .registers
1424                    .irq1_inte
1425                    .modify(IRQ1_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1426                InterruptSources::Sm2RXNotEmpty => self
1427                    .registers
1428                    .irq1_inte
1429                    .modify(IRQ1_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1430                InterruptSources::Sm3RXNotEmpty => self
1431                    .registers
1432                    .irq1_inte
1433                    .modify(IRQ1_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1434            }
1435        } else {
1436            debug!("IRQ Index invalid - must be 0 or 1");
1437        }
1438    }
1439
1440    /// Checks if a PIO interrupt is set.
1441    pub fn interrupt_get(&self, irq_num: u32) -> bool {
1442        let mut temp = 0;
1443        match irq_num {
1444            0 => temp = self.registers.irq.read(IRQ::IRQ0),
1445            1 => temp = self.registers.irq.read(IRQ::IRQ1),
1446            2 => temp = self.registers.irq.read(IRQ::IRQ2),
1447            3 => temp = self.registers.irq.read(IRQ::IRQ3),
1448            4 => temp = self.registers.irq.read(IRQ::IRQ4),
1449            5 => temp = self.registers.irq.read(IRQ::IRQ5),
1450            6 => temp = self.registers.irq.read(IRQ::IRQ6),
1451            7 => temp = self.registers.irq.read(IRQ::IRQ7),
1452            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1453        }
1454        temp != 0
1455    }
1456
1457    /// Clear a PIO interrupt.
1458    pub fn interrupt_clear(&self, irq_num: u32) {
1459        match irq_num {
1460            0 => self.registers.irq.modify(IRQ::IRQ0.val(1)),
1461            1 => self.registers.irq.modify(IRQ::IRQ1.val(1)),
1462            2 => self.registers.irq.modify(IRQ::IRQ2.val(1)),
1463            3 => self.registers.irq.modify(IRQ::IRQ3.val(1)),
1464            4 => self.registers.irq.modify(IRQ::IRQ4.val(1)),
1465            5 => self.registers.irq.modify(IRQ::IRQ5.val(1)),
1466            6 => self.registers.irq.modify(IRQ::IRQ6.val(1)),
1467            7 => self.registers.irq.modify(IRQ::IRQ7.val(1)),
1468            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1469        }
1470    }
1471
1472    /// Handle interrupts
1473    pub fn handle_interrupt(&self) {
1474        let ints = &self.registers.irq0_ints;
1475        for (sm, irq) in self.sms.iter().zip([
1476            IRQ0_INTS::SM0_TXNFULL,
1477            IRQ0_INTS::SM1_TXNFULL,
1478            IRQ0_INTS::SM2_TXNFULL,
1479            IRQ0_INTS::SM3_TXNFULL,
1480        ]) {
1481            if ints.is_set(irq) {
1482                sm.handle_tx_interrupt();
1483            }
1484        }
1485        for (sm, irq) in self.sms.iter().zip([
1486            IRQ0_INTS::SM0_RXNEMPTY,
1487            IRQ0_INTS::SM1_RXNEMPTY,
1488            IRQ0_INTS::SM2_RXNEMPTY,
1489            IRQ0_INTS::SM3_RXNEMPTY,
1490        ]) {
1491            if ints.is_set(irq) {
1492                sm.handle_rx_interrupt();
1493            }
1494        }
1495    }
1496
1497    /// Adds a program to PIO.
1498    /// Call this with `add_program(Some(0), include_bytes!("path_to_file"))`.
1499    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1500    /// => program: the program to load into the PIO
1501    /// Returns `LoadedProgram` which contains information about program location and length.
1502    pub fn add_program(
1503        &self,
1504        origin: Option<usize>,
1505        program: &[u8],
1506    ) -> Result<LoadedProgram, ProgramError> {
1507        let mut program_u16: [u16; NUMBER_INSTR_MEMORY_LOCATIONS / 2] =
1508            [0; NUMBER_INSTR_MEMORY_LOCATIONS / 2];
1509        for (i, chunk) in program.chunks(2).enumerate() {
1510            program_u16[i] = ((chunk[0] as u16) << 8) | (chunk[1] as u16);
1511        }
1512
1513        self.add_program16(origin, &program_u16[0..program.len() / 2])
1514    }
1515
1516    /// Adds a program to PIO.
1517    /// Takes `&[u16]` as input, cause pio-asm operations are 16bit.
1518    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1519    /// => program: the program to load into the PIO
1520    /// Returns `LoadedProgram` which contains information about program location and size.
1521    pub fn add_program16(
1522        &self,
1523        origin: Option<usize>,
1524        program: &[u16],
1525    ) -> Result<LoadedProgram, ProgramError> {
1526        // if origin is not set, try naively to find an empty space
1527        match origin {
1528            Some(origin) => {
1529                assert!(origin < NUMBER_INSTR_MEMORY_LOCATIONS);
1530                self.try_load_program_at(origin, program)
1531                    .map_err(|_| ProgramError::AddrInUse(origin))
1532            }
1533            None => {
1534                for origin in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1535                    if let res @ Ok(_) = self.try_load_program_at(origin, program) {
1536                        return res;
1537                    }
1538                }
1539                Err(ProgramError::InsufficientSpace)
1540            }
1541        }
1542    }
1543
1544    /// Try to load program at a specific origin, relocate operations if necessary.
1545    /// Only for internals, use `add_program` or `add_program16` instead.
1546    /// => origin: the address in the PIO instruction memory to start the program at
1547    /// => program: the program to load into the PIO
1548    /// Returns Ok(()) if the program was loaded successfully, otherwise an error.
1549    fn try_load_program_at(
1550        &self,
1551        origin: usize,
1552        program: &[u16],
1553    ) -> Result<LoadedProgram, ProgramError> {
1554        // Relocate program
1555        let program = RelocatedProgram::new(program.iter(), origin);
1556        let mut used_mask = 0;
1557        for (i, instr) in program.enumerate() {
1558            // wrapping around the end of program memory is valid
1559            let addr = (i + origin) % 32;
1560            let mask = 1 << addr;
1561            if (self.instructions_used.get() | used_mask) & mask != 0 {
1562                return Err(ProgramError::AddrInUse(addr));
1563            }
1564            self.registers.instr_mem[addr]
1565                .instr_mem
1566                .modify(INSTR_MEMx::INSTR_MEM.val(instr as u32));
1567            used_mask |= mask;
1568        }
1569        // update the mask of used instructions slots
1570        self.instructions_used
1571            .set(self.instructions_used.get() | used_mask);
1572        Ok(LoadedProgram {
1573            used_memory: used_mask,
1574            origin,
1575        })
1576    }
1577
1578    /// Clears all of a PIO instance's instruction memory.
1579    pub fn clear_instr_registers(&self) {
1580        for i in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1581            self.registers.instr_mem[i]
1582                .instr_mem
1583                .modify(INSTR_MEMx::INSTR_MEM::CLEAR);
1584        }
1585    }
1586
1587    /// Initialize a new PIO with the same default configuration for all four state machines.
1588    pub fn init(&self) {
1589        let default_config: StateMachineConfiguration = StateMachineConfiguration::default();
1590        for state_machine in self.sms.iter() {
1591            state_machine.config(&default_config);
1592        }
1593        self.clear_instr_registers()
1594    }
1595}
1596
1597mod examples {
1598    use super::{
1599        debug, Pio, RPGpio, RPGpioPin, Readable, SMNumber, SMx_EXECCTRL, SMx_INSTR, SMx_PINCTRL,
1600        StateMachineConfiguration, DBG_PADOUT, FDEBUG,
1601    };
1602
1603    impl RPGpio {
1604        fn from_u32(value: u32) -> RPGpio {
1605            match value {
1606                0 => RPGpio::GPIO0,
1607                1 => RPGpio::GPIO1,
1608                2 => RPGpio::GPIO2,
1609                3 => RPGpio::GPIO3,
1610                4 => RPGpio::GPIO4,
1611                5 => RPGpio::GPIO5,
1612                6 => RPGpio::GPIO6,
1613                7 => RPGpio::GPIO7,
1614                8 => RPGpio::GPIO8,
1615                9 => RPGpio::GPIO9,
1616                10 => RPGpio::GPIO10,
1617                11 => RPGpio::GPIO11,
1618                12 => RPGpio::GPIO12,
1619                13 => RPGpio::GPIO13,
1620                14 => RPGpio::GPIO14,
1621                15 => RPGpio::GPIO15,
1622                16 => RPGpio::GPIO16,
1623                17 => RPGpio::GPIO17,
1624                18 => RPGpio::GPIO18,
1625                19 => RPGpio::GPIO19,
1626                20 => RPGpio::GPIO20,
1627                21 => RPGpio::GPIO21,
1628                22 => RPGpio::GPIO22,
1629                23 => RPGpio::GPIO23,
1630                24 => RPGpio::GPIO24,
1631                25 => RPGpio::GPIO25,
1632                26 => RPGpio::GPIO26,
1633                27 => RPGpio::GPIO27,
1634                28 => RPGpio::GPIO28,
1635                29 => RPGpio::GPIO29,
1636                _ => panic!(
1637                    "Unknown value for GPIO pin: {} (should be from 0 to 29)",
1638                    value
1639                ),
1640            }
1641        }
1642    }
1643
1644    impl Pio {
1645        // # Examples
1646        /// Used for the examples in the pico explorer base main.rs file.
1647
1648        pub fn blinking_hello_program_init(
1649            &self,
1650            sm_number: SMNumber,
1651            pin: u32,
1652            config: &StateMachineConfiguration,
1653        ) {
1654            let sm = &self.sms[sm_number as usize];
1655            sm.config(config);
1656            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1657            sm.set_enabled(false);
1658            sm.set_pins_dirs(pin, 1, true);
1659            sm.set_set_pins(pin, 1);
1660            sm.init();
1661            sm.set_enabled(true);
1662        }
1663
1664        pub fn blink_program_init(
1665            &self,
1666            sm_number: SMNumber,
1667            pin: u32,
1668            config: &StateMachineConfiguration,
1669        ) {
1670            let sm = &self.sms[sm_number as usize];
1671            sm.config(config);
1672            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1673            sm.set_enabled(false);
1674            sm.set_pins_dirs(pin, 1, true);
1675            sm.set_set_pins(pin, 1);
1676            sm.init();
1677            sm.set_enabled(true);
1678        }
1679
1680        pub fn sideset_program_init(
1681            &self,
1682            sm_number: SMNumber,
1683            pin: u32,
1684            config: &StateMachineConfiguration,
1685        ) {
1686            let sm = &self.sms[sm_number as usize];
1687            sm.config(config);
1688            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1689            self.gpio_init(&RPGpioPin::new(RPGpio::GPIO7));
1690            sm.set_enabled(false);
1691            sm.set_pins_dirs(pin, 1, true);
1692            sm.set_pins_dirs(7, 1, true);
1693            sm.set_set_pins(pin, 1);
1694            sm.set_side_set_pins(7, 1, false, true);
1695            sm.init();
1696            sm.set_enabled(true);
1697        }
1698
1699        pub fn hello_program_init(
1700            &self,
1701            sm_number: SMNumber,
1702            pin1: u32,
1703            pin2: u32,
1704            config: &StateMachineConfiguration,
1705        ) {
1706            let sm = &self.sms[sm_number as usize];
1707            // This is used to turn on specifically GPIOs 6 and 7 - LSB is for GPIO 0, next bit is for GPIO 1 etc.
1708            let turn_on_gpio_6_7 = 0b11000000;
1709            sm.config(config);
1710            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin1)));
1711            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin2)));
1712            sm.set_enabled(false);
1713            sm.set_pins_dirs(pin1, 1, true);
1714            sm.set_pins_dirs(pin2, 1, true);
1715            sm.init();
1716            sm.set_enabled(true);
1717            sm.push_blocking(turn_on_gpio_6_7).ok();
1718            sm.push_blocking(0).ok();
1719        }
1720
1721        pub fn pwm_program_init(
1722            &self,
1723            sm_number: SMNumber,
1724            pin: u32,
1725            pwm_period: u32,
1726            config: &StateMachineConfiguration,
1727        ) {
1728            let sm = &self.sms[sm_number as usize];
1729            // "pull" command created by pioasm
1730            let pull_command = 0x8080_u16;
1731            // "out isr, 32" command created by pioasm
1732            let out_isr_32_command = 0x60c0_u16;
1733            sm.config(config);
1734            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1735            sm.set_enabled(false);
1736            sm.set_pins_dirs(pin, 1, true);
1737            sm.set_side_set_pins(pin, 1, false, true);
1738            sm.init();
1739            sm.push_blocking(pwm_period).ok();
1740            sm.exec(pull_command);
1741            sm.exec(out_isr_32_command);
1742            sm.set_enabled(true);
1743        }
1744
1745        // # Debugging
1746        /// Returns current instruction running on the state machine.
1747        pub fn read_instr(&self, sm_number: SMNumber) -> u32 {
1748            self.registers.sm[sm_number as usize]
1749                .instr
1750                .read(SMx_INSTR::INSTR)
1751        }
1752
1753        pub fn read_sideset_reg(&self, sm_number: SMNumber) {
1754            debug!(
1755                "{}",
1756                self.registers.sm[sm_number as usize]
1757                    .pinctrl
1758                    .read(SMx_PINCTRL::SIDESET_COUNT)
1759            );
1760            debug!(
1761                "{}",
1762                self.registers.sm[sm_number as usize]
1763                    .execctrl
1764                    .read(SMx_EXECCTRL::SIDE_EN)
1765            );
1766            debug!(
1767                "{}",
1768                self.registers.sm[sm_number as usize]
1769                    .execctrl
1770                    .read(SMx_EXECCTRL::SIDE_PINDIR)
1771            );
1772            debug!(
1773                "{}",
1774                self.registers.sm[sm_number as usize]
1775                    .pinctrl
1776                    .read(SMx_PINCTRL::SIDESET_BASE)
1777            );
1778        }
1779
1780        pub fn read_dbg_padout(&self) -> u32 {
1781            self.registers.dbg_padout.read(DBG_PADOUT::DBG_PADOUT)
1782        }
1783
1784        pub fn read_fdebug(&self, tx: bool, stall: bool) -> u32 {
1785            if tx {
1786                if stall {
1787                    self.registers.fdebug.read(FDEBUG::TXSTALL)
1788                } else {
1789                    self.registers.fdebug.read(FDEBUG::TXOVER)
1790                }
1791            } else if stall {
1792                self.registers.fdebug.read(FDEBUG::RXSTALL)
1793            } else {
1794                self.registers.fdebug.read(FDEBUG::RXUNDER)
1795            }
1796        }
1797    }
1798}