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(11) NUMBITS(1) [],
447    SM2 OFFSET(10) NUMBITS(1) [],
448    SM1 OFFSET(9) NUMBITS(1) [],
449    SM0 OFFSET(8) NUMBITS(1) [],
450    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
451    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
452    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
453    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
454    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
455    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
456    SM1_RXNEMPTY OFFSET(1) 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
563#[derive(Clone, Copy)]
564pub struct LoadedProgram {
565    used_memory: u32,
566    origin: usize,
567}
568
569#[derive(Clone, Copy, PartialEq, Eq, Debug)]
570pub enum ProgramError {
571    /// Insufficient consecutive free instruction space to load program.
572    InsufficientSpace,
573    /// Loading a program would overwrite the existing one
574    AddrInUse(usize),
575}
576
577/// There are a total of 4 State Machines per PIO.
578#[derive(Clone, Copy, PartialEq, Debug)]
579pub enum SMNumber {
580    SM0 = 0,
581    SM1 = 1,
582    SM2 = 2,
583    SM3 = 3,
584}
585
586/// Array of all SMNumbers, used for convenience in Pio constructor
587const SM_NUMBERS: [SMNumber; 4] = [SMNumber::SM0, SMNumber::SM1, SMNumber::SM2, SMNumber::SM3];
588
589/// There can be 2 PIOs per RP2040.
590#[derive(Clone, Copy, PartialEq)]
591pub enum PIONumber {
592    PIO0 = 0,
593    PIO1 = 1,
594}
595
596/// The FIFO queues can be joined together for twice the length in one direction.
597#[derive(PartialEq)]
598pub enum PioFifoJoin {
599    PioFifoJoinNone = 0,
600    PioFifoJoinTx = 1,
601    PioFifoJoinRx = 2,
602}
603
604/// PIO interrupt source numbers for PIO related interrupts
605#[derive(PartialEq)]
606pub enum InterruptSources {
607    Interrupt0 = 0,
608    Interrupt1 = 1,
609    Interrupt2 = 2,
610    Interrupt3 = 3,
611    Sm0TXNotFull = 4,
612    Sm1TXNotFull = 5,
613    Sm2TXNotFull = 6,
614    Sm3TXNotFull = 7,
615    Sm0RXNotEmpty = 8,
616    Sm1RXNotEmpty = 9,
617    Sm2RXNotEmpty = 10,
618    Sm3RXNotEmpty = 11,
619}
620
621pub trait PioTxClient {
622    fn on_buffer_space_available(&self);
623}
624
625pub trait PioRxClient {
626    fn on_data_received(&self, data: u32);
627}
628
629#[derive(Clone, Copy, Debug, Default)]
630enum StateMachineState {
631    #[default]
632    Ready,
633    Waiting,
634}
635
636pub struct StateMachine {
637    sm_number: SMNumber,
638    registers: StaticRef<PioRegisters>,
639    xor_registers: StaticRef<PioRegisters>,
640    set_registers: StaticRef<PioRegisters>,
641    tx_state: Cell<StateMachineState>,
642    tx_client: OptionalCell<&'static dyn PioTxClient>,
643    rx_state: Cell<StateMachineState>,
644    rx_client: OptionalCell<&'static dyn PioRxClient>,
645}
646
647impl StateMachine {
648    fn new(
649        sm_id: SMNumber,
650        registers: StaticRef<PioRegisters>,
651        xor_registers: StaticRef<PioRegisters>,
652        set_registers: StaticRef<PioRegisters>,
653    ) -> StateMachine {
654        StateMachine {
655            sm_number: sm_id,
656            registers,
657            xor_registers,
658            set_registers,
659            tx_state: Cell::new(StateMachineState::Ready),
660            tx_client: OptionalCell::empty(),
661            rx_state: Cell::new(StateMachineState::Ready),
662            rx_client: OptionalCell::empty(),
663        }
664    }
665
666    /// State machine configuration with any config structure.
667    pub fn config(&self, config: &StateMachineConfiguration) {
668        self.set_in_pins(config.in_pins_base);
669        self.set_out_pins(config.out_pins_base, config.out_pins_count);
670        self.set_set_pins(config.set_pins_base, config.set_pins_count);
671        self.set_side_set_pins(
672            config.side_set_base,
673            config.side_set_bit_count,
674            config.side_set_opt_enable,
675            config.side_set_pindirs,
676        );
677        self.set_in_shift(
678            config.in_shift_direction_right,
679            config.in_autopush,
680            config.in_push_threshold,
681        );
682        self.set_out_shift(
683            config.out_shift_direction_right,
684            config.out_autopull,
685            config.out_pull_threshold,
686        );
687        self.set_jmp_pin(config.jmp_pin);
688        self.set_wrap(config.wrap_to, config.wrap);
689        self.set_mov_status(config.mov_status_sel, config.mov_status_n);
690        self.set_out_special(
691            config.out_special_sticky,
692            config.out_special_has_enable_pin,
693            config.out_special_enable_pin_index,
694        );
695        self.set_clkdiv_int_frac(config.div_int, config.div_frac);
696    }
697
698    /// Set tx client for a state machine.
699    pub fn set_tx_client(&self, client: &'static dyn PioTxClient) {
700        self.tx_client.set(client);
701    }
702
703    /// Set rx client for a state machine.
704    pub fn set_rx_client(&self, client: &'static dyn PioRxClient) {
705        self.rx_client.set(client);
706    }
707
708    /// Set every config for the IN pins.
709    ///
710    /// in_base => the starting location for the input pins
711    pub fn set_in_pins(&self, in_base: u32) {
712        self.registers.sm[self.sm_number as usize]
713            .pinctrl
714            .modify(SMx_PINCTRL::IN_BASE.val(in_base));
715    }
716
717    /// Set every config for the SET pins.
718    ///
719    /// set_base => the starting location for the SET pins
720    /// set_count => the number of SET pins
721    pub fn set_set_pins(&self, set_base: u32, set_count: u32) {
722        self.registers.sm[self.sm_number as usize]
723            .pinctrl
724            .modify(SMx_PINCTRL::SET_BASE.val(set_base));
725        self.registers.sm[self.sm_number as usize]
726            .pinctrl
727            .modify(SMx_PINCTRL::SET_COUNT.val(set_count));
728    }
729
730    /// Set every config for the OUT pins.
731    ///
732    /// out_base => the starting location for the OUT pins
733    /// out_count => the number of OUT pins
734    pub fn set_out_pins(&self, out_base: u32, out_count: u32) {
735        self.registers.sm[self.sm_number as usize]
736            .pinctrl
737            .modify(SMx_PINCTRL::OUT_BASE.val(out_base));
738        self.registers.sm[self.sm_number as usize]
739            .pinctrl
740            .modify(SMx_PINCTRL::OUT_COUNT.val(out_count));
741    }
742
743    /// Setup 'in' shifting parameters.
744    ///
745    ///  shift_right => true to shift ISR to right or false to shift to left
746    ///  autopush => true to enable, false to disable
747    ///  push_threshold => threshold in bits to shift in before auto/conditional re-pushing of the ISR
748    pub fn set_in_shift(&self, shift_right: bool, autopush: bool, push_threshold: u32) {
749        self.registers.sm[self.sm_number as usize]
750            .shiftctrl
751            .modify(SMx_SHIFTCTRL::IN_SHIFTDIR.val(shift_right.into()));
752        self.registers.sm[self.sm_number as usize]
753            .shiftctrl
754            .modify(SMx_SHIFTCTRL::AUTOPUSH.val(autopush.into()));
755        self.registers.sm[self.sm_number as usize]
756            .shiftctrl
757            .modify(SMx_SHIFTCTRL::PUSH_THRESH.val(push_threshold));
758    }
759
760    /// Setup 'out' shifting parameters.
761    ///
762    /// shift_right => `true` to shift OSR to right or false to shift to left
763    /// autopull => true to enable, false to disable
764    /// pull_threshold => threshold in bits to shift out before auto/conditional re-pulling of the OSR
765    pub fn set_out_shift(&self, shift_right: bool, autopull: bool, pull_threshold: u32) {
766        self.registers.sm[self.sm_number as usize]
767            .shiftctrl
768            .modify(SMx_SHIFTCTRL::OUT_SHIFTDIR.val(shift_right.into()));
769        self.registers.sm[self.sm_number as usize]
770            .shiftctrl
771            .modify(SMx_SHIFTCTRL::AUTOPULL.val(autopull.into()));
772        self.registers.sm[self.sm_number as usize]
773            .shiftctrl
774            .modify(SMx_SHIFTCTRL::PULL_THRESH.val(pull_threshold));
775    }
776
777    /// Set special OUT operations in a state machine.
778    ///
779    /// sticky
780    /// => true to enable sticky output (rere-asserting most recent OUT/SET pin values on subsequent cycles)
781    /// => false to disable sticky output
782    /// has_enable_pin
783    /// => true to enable auxiliary OUT enable pin
784    /// => false to disable auxiliary OUT enable pin
785    /// enable_pin_index => pin index for auxiliary OUT enable
786    pub fn set_out_special(&self, sticky: bool, has_enable_pin: bool, enable_pin_index: u32) {
787        self.registers.sm[self.sm_number as usize]
788            .execctrl
789            .modify(SMx_EXECCTRL::OUT_STICKY.val(sticky as u32));
790        self.registers.sm[self.sm_number as usize]
791            .execctrl
792            .modify(SMx_EXECCTRL::INLINE_OUT_EN.val(has_enable_pin as u32));
793        self.registers.sm[self.sm_number as usize]
794            .execctrl
795            .modify(SMx_EXECCTRL::OUT_EN_SEL.val(enable_pin_index));
796    }
797
798    /// Set the 'jmp' pin.
799    ///
800    /// pin => the raw GPIO pin number to use as the source for a jmp pin instruction
801    pub fn set_jmp_pin(&self, pin: u32) {
802        self.registers.sm[self.sm_number as usize]
803            .execctrl
804            .modify(SMx_EXECCTRL::JMP_PIN.val(pin));
805    }
806
807    /// Set the clock divider for a state machine.
808    ///
809    /// div_int => Integer part of the divisor
810    /// div_frac => Fractional part in 1/256ths
811    pub fn set_clkdiv_int_frac(&self, div_int: u32, div_frac: u32) {
812        self.registers.sm[self.sm_number as usize]
813            .clkdiv
814            .modify(SMx_CLKDIV::INT.val(div_int));
815        self.registers.sm[self.sm_number as usize]
816            .clkdiv
817            .modify(SMx_CLKDIV::FRAC.val(div_frac));
818    }
819
820    /// Setup the FIFO joining in a state machine.
821    ///
822    /// fifo_join => specifies the join type - see the `PioFifoJoin` type
823    pub fn set_fifo_join(&self, fifo_join: PioFifoJoin) {
824        if fifo_join == PioFifoJoin::PioFifoJoinRx {
825            self.registers.sm[self.sm_number as usize]
826                .shiftctrl
827                .modify(SMx_SHIFTCTRL::FJOIN_RX.val(fifo_join as u32));
828        } else if fifo_join == PioFifoJoin::PioFifoJoinTx {
829            self.registers.sm[self.sm_number as usize]
830                .shiftctrl
831                .modify(SMx_SHIFTCTRL::FJOIN_TX.val(fifo_join as u32));
832        }
833    }
834
835    /// Set every config for the SIDESET pins.
836    ///
837    /// sideset_base => the starting location for the SIDESET pins
838    /// bit_count => number of SIDESET bits per instruction - max 5
839    /// optional
840    /// => true to use the topmost sideset bit as a flag for whether to apply side set on that instruction
841    /// => false to use sideset with every instruction
842    /// pindirs
843    /// => true to affect pin direction
844    /// => false to affect value of a pin
845    pub fn set_side_set_pins(
846        &self,
847        sideset_base: u32,
848        bit_count: u32,
849        optional: bool,
850        pindirs: bool,
851    ) {
852        self.registers.sm[self.sm_number as usize]
853            .pinctrl
854            .modify(SMx_PINCTRL::SIDESET_BASE.val(sideset_base));
855        self.registers.sm[self.sm_number as usize]
856            .pinctrl
857            .modify(SMx_PINCTRL::SIDESET_COUNT.val(bit_count));
858        self.registers.sm[self.sm_number as usize]
859            .execctrl
860            .modify(SMx_EXECCTRL::SIDE_EN.val(optional as u32));
861        self.registers.sm[self.sm_number as usize]
862            .execctrl
863            .modify(SMx_EXECCTRL::SIDE_PINDIR.val(pindirs as u32));
864    }
865
866    /// Use a state machine to set the same pin direction for multiple consecutive pins for the PIO instance.
867    /// This is the pio_sm_set_consecutive_pindirs function from the pico sdk, renamed to be more clear.
868    ///
869    /// pin => starting pin
870    /// count => how many pins (including the base) should be changed
871    /// is_out
872    /// => true to set the pin as OUT
873    /// => false to set the pin as IN
874    pub fn set_pins_dirs(&self, mut pin: u32, mut count: u32, is_out: bool) {
875        // "set pindirs, 0" command created by pioasm
876        let set_pindirs_0: u16 = 0b1110000010000000;
877        self.with_paused(|| {
878            let mut pindir_val: u8 = 0x00;
879            if is_out {
880                pindir_val = 0x1f;
881            }
882            while count > 5 {
883                self.registers.sm[self.sm_number as usize]
884                    .pinctrl
885                    .modify(SMx_PINCTRL::SET_COUNT.val(5));
886                self.registers.sm[self.sm_number as usize]
887                    .pinctrl
888                    .modify(SMx_PINCTRL::SET_BASE.val(pin));
889                self.exec((set_pindirs_0) | (pindir_val as u16));
890                count -= 5;
891                pin = (pin + 5) & 0x1f;
892            }
893            self.registers.sm[self.sm_number as usize]
894                .pinctrl
895                .modify(SMx_PINCTRL::SET_COUNT.val(count));
896            self.registers.sm[self.sm_number as usize]
897                .pinctrl
898                .modify(SMx_PINCTRL::SET_BASE.val(pin));
899            self.exec((set_pindirs_0) | (pindir_val as u16));
900        });
901    }
902
903    /// Sets pin output values. Pauses the state machine to run `SET` commands
904    /// and temporarily unsets the `OUT_STICKY` bit to avoid side effects.
905    ///
906    /// pins => pins to set the value for
907    /// high => true to set the pin high
908    pub fn set_pins(&self, pins: &[&RPGpioPin<'_>], high: bool) {
909        self.with_paused(|| {
910            for pin in pins {
911                self.registers.sm[self.sm_number as usize]
912                    .pinctrl
913                    .modify(SMx_PINCTRL::SET_BASE.val(pin.pin() as u32));
914                self.registers.sm[self.sm_number as usize]
915                    .pinctrl
916                    .modify(SMx_PINCTRL::SET_COUNT.val(1));
917
918                self.exec(0b11100_000_000_00000 | high as u16);
919            }
920        });
921    }
922
923    /// Set the wrap addresses for a state machine.
924    ///
925    /// wrap_target => the instruction memory address to wrap to
926    /// wrap => the instruction memory address after which the program counters wraps to the target
927    pub fn set_wrap(&self, wrap_target: u32, wrap: u32) {
928        self.registers.sm[self.sm_number as usize]
929            .execctrl
930            .modify(SMx_EXECCTRL::WRAP_BOTTOM.val(wrap_target));
931        self.registers.sm[self.sm_number as usize]
932            .execctrl
933            .modify(SMx_EXECCTRL::WRAP_TOP.val(wrap));
934    }
935
936    /// Resets the state machine to a consistent state and configures it.
937    pub fn init(&self) {
938        self.clear_fifos();
939        self.restart();
940        self.clkdiv_restart();
941        self.registers.sm[self.sm_number as usize]
942            .instr
943            .modify(SMx_INSTR::INSTR.val(0));
944    }
945
946    /// Restart a state machine.
947    pub fn restart(&self) {
948        match self.sm_number {
949            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::SM0_RESTART::SET),
950            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::SM1_RESTART::SET),
951            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::SM2_RESTART::SET),
952            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::SM3_RESTART::SET),
953        }
954    }
955
956    /// Clear a state machine’s TX and RX FIFOs.
957    pub fn clear_fifos(&self) {
958        self.xor_registers.sm[self.sm_number as usize]
959            .shiftctrl
960            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
961        self.xor_registers.sm[self.sm_number as usize]
962            .shiftctrl
963            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
964    }
965
966    /// Restart a state machine's clock divider.
967    pub fn clkdiv_restart(&self) {
968        match self.sm_number {
969            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::CLKDIV0_RESTART::SET),
970            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::CLKDIV1_RESTART::SET),
971            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::CLKDIV2_RESTART::SET),
972            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::CLKDIV3_RESTART::SET),
973        }
974    }
975
976    /// Returns true if the TX FIFO is full.
977    pub fn tx_full(&self) -> bool {
978        let field = match self.sm_number {
979            SMNumber::SM0 => FSTAT::TXFULL0,
980            SMNumber::SM1 => FSTAT::TXFULL1,
981            SMNumber::SM2 => FSTAT::TXFULL2,
982            SMNumber::SM3 => FSTAT::TXFULL3,
983        };
984        self.registers.fstat.read(field) != 0
985    }
986
987    /// Returns true if the RX FIFO is empty.
988    pub fn rx_empty(&self) -> bool {
989        let field = match self.sm_number {
990            SMNumber::SM0 => FSTAT::RXEMPTY0,
991            SMNumber::SM1 => FSTAT::RXEMPTY1,
992            SMNumber::SM2 => FSTAT::RXEMPTY2,
993            SMNumber::SM3 => FSTAT::RXEMPTY3,
994        };
995        self.registers.fstat.read(field) != 0
996    }
997
998    /// Returns true if the TX FIFO is empty.
999    pub fn tx_empty(&self) -> bool {
1000        let field = match self.sm_number {
1001            SMNumber::SM0 => FSTAT::TXEMPTY0,
1002            SMNumber::SM1 => FSTAT::TXEMPTY1,
1003            SMNumber::SM2 => FSTAT::TXEMPTY2,
1004            SMNumber::SM3 => FSTAT::TXEMPTY3,
1005        };
1006        self.registers.fstat.read(field) != 0
1007    }
1008
1009    /// Immediately execute an instruction on a state machine.
1010    ///
1011    /// => instr: the instruction to execute
1012    /// Implicitly restricted size of instr to u16, cause it's the size pio asm instr
1013    pub fn exec(&self, instr: u16) {
1014        self.registers.sm[self.sm_number as usize]
1015            .instr
1016            .modify(SMx_INSTR::INSTR.val(instr as u32));
1017    }
1018
1019    /// Executes a program on a state machine.
1020    /// Jumps to the instruction at given address and runs the program.
1021    ///
1022    /// => program: a program loaded to PIO
1023    /// => wrap: true to wrap the program, so it runs in loop
1024    pub fn exec_program(&self, program: LoadedProgram, wrap: bool) {
1025        if wrap {
1026            self.set_wrap(
1027                program.origin as u32,
1028                program.origin as u32 + program.used_memory.count_ones(),
1029            );
1030        }
1031        self.exec((program.origin as u16) & 0x1fu16)
1032    }
1033
1034    /// Set source for 'mov status' in a state machine.
1035    ///
1036    /// status_sel => comparison used for the `MOV x, STATUS` instruction
1037    /// status_n => comparison level for the `MOV x, STATUS` instruction
1038    pub fn set_mov_status(&self, status_sel: PioMovStatusType, status_n: u32) {
1039        self.registers.sm[self.sm_number as usize]
1040            .execctrl
1041            .modify(SMx_EXECCTRL::STATUS_SEL.val(status_sel as u32));
1042        self.registers.sm[self.sm_number as usize]
1043            .execctrl
1044            .modify(SMx_EXECCTRL::STATUS_N.val(status_n));
1045    }
1046
1047    /// Set a state machine's state to enabled or to disabled.
1048    ///
1049    /// enabled => true to enable the state machine
1050    pub fn set_enabled(&self, enabled: bool) {
1051        match self.sm_number {
1052            SMNumber::SM0 => self.registers.ctrl.modify(match enabled {
1053                true => CTRL::SM0_ENABLE::SET,
1054                false => CTRL::SM0_ENABLE::CLEAR,
1055            }),
1056            SMNumber::SM1 => self.registers.ctrl.modify(match enabled {
1057                true => CTRL::SM1_ENABLE::SET,
1058                false => CTRL::SM1_ENABLE::CLEAR,
1059            }),
1060            SMNumber::SM2 => self.registers.ctrl.modify(match enabled {
1061                true => CTRL::SM2_ENABLE::SET,
1062                false => CTRL::SM2_ENABLE::CLEAR,
1063            }),
1064            SMNumber::SM3 => self.registers.ctrl.modify(match enabled {
1065                true => CTRL::SM3_ENABLE::SET,
1066                false => CTRL::SM3_ENABLE::CLEAR,
1067            }),
1068        }
1069    }
1070
1071    /// Is state machine enabled.
1072    pub fn is_enabled(&self) -> bool {
1073        let field = match self.sm_number {
1074            SMNumber::SM0 => CTRL::SM0_ENABLE,
1075            SMNumber::SM1 => CTRL::SM1_ENABLE,
1076            SMNumber::SM2 => CTRL::SM2_ENABLE,
1077            SMNumber::SM3 => CTRL::SM3_ENABLE,
1078        };
1079        self.registers.ctrl.read(field) != 0
1080    }
1081
1082    /// Runs function with the state machine paused.
1083    /// Keeps pinctrl and execctrl of the SM the same during execution
1084    fn with_paused(&self, f: impl FnOnce()) {
1085        let enabled = self.is_enabled();
1086        self.set_enabled(false);
1087
1088        let pio_sm = &self.registers.sm[self.sm_number as usize];
1089
1090        let pinctrl = pio_sm.pinctrl.get();
1091        let execctrl = pio_sm.execctrl.get();
1092        // Hold pins value set by latest OUT/SET op
1093        pio_sm.execctrl.modify(SMx_EXECCTRL::OUT_STICKY::CLEAR);
1094
1095        f();
1096
1097        pio_sm.pinctrl.set(pinctrl);
1098        pio_sm.execctrl.set(execctrl);
1099        self.set_enabled(enabled);
1100    }
1101
1102    /// Write a word of data to a state machine’s TX FIFO.
1103    /// If the FIFO is full, the client will be notified when space is available.
1104    ///
1105    /// => data: the data to write to the FIFO
1106    pub fn push(&self, data: u32) -> Result<(), ErrorCode> {
1107        match self.tx_state.get() {
1108            StateMachineState::Ready => {
1109                if self.tx_full() {
1110                    // TX queue is full, set interrupt
1111                    let field = match self.sm_number {
1112                        SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::SET,
1113                        SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::SET,
1114                        SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::SET,
1115                        SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::SET,
1116                    };
1117                    self.registers.irq0_inte.modify(field);
1118                    self.tx_state.set(StateMachineState::Waiting);
1119                    Err(ErrorCode::BUSY)
1120                } else {
1121                    self.registers.txf[self.sm_number as usize].set(data);
1122                    Ok(())
1123                }
1124            }
1125            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1126        }
1127    }
1128
1129    /// Wait until a state machine's TX FIFO is empty, then write a word of data to it.
1130    /// If state machine is disabled and there is no space, an error will be returned.
1131    /// If SM is stalled on RX or in loop, this will block forever.
1132    ///
1133    /// => data: the data to write to the FIFO
1134    pub fn push_blocking(&self, data: u32) -> Result<(), ErrorCode> {
1135        if self.tx_full() && !self.is_enabled() {
1136            return Err(ErrorCode::OFF);
1137        }
1138        while self.tx_full() {}
1139        self.registers.txf[self.sm_number as usize].set(data);
1140        Ok(())
1141    }
1142
1143    /// Read a word of data from a state machine’s RX FIFO.
1144    /// If the FIFO is empty, the client will be notified when data is available.
1145    pub fn pull(&self) -> Result<u32, ErrorCode> {
1146        match self.rx_state.get() {
1147            StateMachineState::Ready => {
1148                if self.rx_empty() {
1149                    // RX queue is empty, set interrupt
1150                    let field = match self.sm_number {
1151                        SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::SET,
1152                        SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::SET,
1153                        SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::SET,
1154                        SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::SET,
1155                    };
1156                    self.registers.irq0_inte.modify(field);
1157                    self.rx_state.set(StateMachineState::Waiting);
1158                    Err(ErrorCode::BUSY)
1159                } else {
1160                    Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1161                }
1162            }
1163            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1164        }
1165    }
1166
1167    /// Reads a word of data from a state machine’s RX FIFO.
1168    /// If state machine is disabled and there is no space, an error will be returned.
1169    /// If SM is stalled on TX or in loop, this will block forever.
1170    pub fn pull_blocking(&self) -> Result<u32, ErrorCode> {
1171        if self.tx_full() && !self.is_enabled() {
1172            return Err(ErrorCode::OFF);
1173        }
1174        while self.rx_empty() {}
1175        Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1176    }
1177
1178    /// Handle a TX interrupt - notify that buffer space is available.
1179    fn handle_tx_interrupt(&self) {
1180        match self.tx_state.get() {
1181            StateMachineState::Waiting => {
1182                // TX queue has emptied, clear interrupt
1183                let field = match self.sm_number {
1184                    SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::CLEAR,
1185                    SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::CLEAR,
1186                    SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::CLEAR,
1187                    SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::CLEAR,
1188                };
1189                self.registers.irq0_inte.modify(field);
1190                self.tx_state.set(StateMachineState::Ready);
1191                self.tx_client.map(|client| {
1192                    client.on_buffer_space_available();
1193                });
1194            }
1195            StateMachineState::Ready => {}
1196        }
1197    }
1198
1199    /// Handle an RX interrupt - notify that data has been received.
1200    fn handle_rx_interrupt(&self) {
1201        match self.rx_state.get() {
1202            StateMachineState::Waiting => {
1203                // RX queue has data, clear interrupt
1204                let field = match self.sm_number {
1205                    SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::CLEAR,
1206                    SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::CLEAR,
1207                    SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::CLEAR,
1208                    SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::CLEAR,
1209                };
1210                self.registers.irq0_inte.modify(field);
1211                self.rx_state.set(StateMachineState::Ready);
1212                self.rx_client.map(|client| {
1213                    client.on_data_received(
1214                        self.registers.rxf[self.sm_number as usize].read(RXFx::RXF),
1215                    );
1216                });
1217            }
1218            StateMachineState::Ready => {}
1219        }
1220    }
1221}
1222
1223pub struct Pio {
1224    registers: StaticRef<PioRegisters>,
1225    pio_number: PIONumber,
1226    sms: [StateMachine; NUMBER_STATE_MACHINES],
1227    instructions_used: Cell<u32>,
1228    _clear_registers: StaticRef<PioRegisters>,
1229}
1230
1231/// 'MOV STATUS' types.
1232#[derive(Clone, Copy)]
1233pub enum PioMovStatusType {
1234    StatusTxLessthan = 0,
1235    StatusRxLessthan = 1,
1236}
1237
1238/// PIO State Machine configuration structure
1239///
1240/// Used to initialize a PIO with all of its state machines.
1241pub struct StateMachineConfiguration {
1242    pub out_pins_count: u32,
1243    pub out_pins_base: u32,
1244    pub set_pins_count: u32,
1245    pub set_pins_base: u32,
1246    pub in_pins_base: u32,
1247    pub side_set_base: u32,
1248    pub side_set_opt_enable: bool,
1249    pub side_set_bit_count: u32,
1250    pub side_set_pindirs: bool,
1251    pub wrap: u32,
1252    pub wrap_to: u32,
1253    pub in_shift_direction_right: bool,
1254    pub in_autopush: bool,
1255    pub in_push_threshold: u32,
1256    pub out_shift_direction_right: bool,
1257    pub out_autopull: bool,
1258    pub out_pull_threshold: u32,
1259    pub jmp_pin: u32,
1260    pub out_special_sticky: bool,
1261    pub out_special_has_enable_pin: bool,
1262    pub out_special_enable_pin_index: u32,
1263    pub mov_status_sel: PioMovStatusType,
1264    pub mov_status_n: u32,
1265    pub div_int: u32,
1266    pub div_frac: u32,
1267}
1268
1269impl Default for StateMachineConfiguration {
1270    fn default() -> Self {
1271        StateMachineConfiguration {
1272            out_pins_count: 32,
1273            out_pins_base: 0,
1274            set_pins_count: 0,
1275            set_pins_base: 0,
1276            in_pins_base: 0,
1277            side_set_base: 0,
1278            side_set_opt_enable: false,
1279            side_set_bit_count: 0,
1280            side_set_pindirs: false,
1281            wrap: 31,
1282            wrap_to: 0,
1283            in_shift_direction_right: true,
1284            in_autopush: false,
1285            in_push_threshold: 32,
1286            out_shift_direction_right: true,
1287            out_autopull: false,
1288            out_pull_threshold: 32,
1289            jmp_pin: 0,
1290            out_special_sticky: false,
1291            out_special_has_enable_pin: false,
1292            out_special_enable_pin_index: 0,
1293            mov_status_sel: PioMovStatusType::StatusTxLessthan,
1294            mov_status_n: 0,
1295            div_int: 0,
1296            div_frac: 0,
1297        }
1298    }
1299}
1300
1301impl Pio {
1302    /// Setup the function select for a GPIO to use output from the given PIO instance.
1303    pub fn gpio_init(&self, pin: &RPGpioPin) {
1304        if self.pio_number == PIONumber::PIO1 {
1305            pin.set_function(GpioFunction::PIO1)
1306        } else {
1307            pin.set_function(GpioFunction::PIO0)
1308        }
1309    }
1310
1311    /// Create a new PIO0 struct.
1312    pub fn new_pio0() -> Self {
1313        Self {
1314            registers: PIO0_BASE,
1315            _clear_registers: PIO0_CLEAR_BASE,
1316            pio_number: PIONumber::PIO0,
1317            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO0_BASE, PIO0_XOR_BASE, PIO0_SET_BASE)),
1318            instructions_used: Cell::new(0),
1319        }
1320    }
1321
1322    /// Create a new PIO1 struct.
1323    pub fn new_pio1() -> Self {
1324        Self {
1325            registers: PIO1_BASE,
1326            _clear_registers: PIO1_CLEAR_BASE,
1327            pio_number: PIONumber::PIO1,
1328            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO1_BASE, PIO1_XOR_BASE, PIO1_SET_BASE)),
1329            instructions_used: Cell::new(0),
1330        }
1331    }
1332
1333    /// Get state machine
1334    pub fn sm(&self, sm_number: SMNumber) -> &StateMachine {
1335        &self.sms[sm_number as usize]
1336    }
1337
1338    /// Enable/Disable a single source on a PIO's IRQ index.
1339    pub fn set_irq_source(
1340        &self,
1341        irq_index: u32,
1342        interrupt_source: InterruptSources,
1343        enabled: bool,
1344    ) {
1345        if irq_index == 0 {
1346            match interrupt_source {
1347                InterruptSources::Interrupt0 => self
1348                    .registers
1349                    .irq0_inte
1350                    .modify(IRQ0_INTE::SM0.val(enabled as u32)),
1351                InterruptSources::Interrupt1 => self
1352                    .registers
1353                    .irq0_inte
1354                    .modify(IRQ0_INTE::SM1.val(enabled as u32)),
1355                InterruptSources::Interrupt2 => self
1356                    .registers
1357                    .irq0_inte
1358                    .modify(IRQ0_INTE::SM2.val(enabled as u32)),
1359                InterruptSources::Interrupt3 => self
1360                    .registers
1361                    .irq0_inte
1362                    .modify(IRQ0_INTE::SM3.val(enabled as u32)),
1363                InterruptSources::Sm0TXNotFull => self
1364                    .registers
1365                    .irq0_inte
1366                    .modify(IRQ0_INTE::SM0_TXNFULL.val(enabled as u32)),
1367                InterruptSources::Sm1TXNotFull => self
1368                    .registers
1369                    .irq0_inte
1370                    .modify(IRQ0_INTE::SM1_TXNFULL.val(enabled as u32)),
1371                InterruptSources::Sm2TXNotFull => self
1372                    .registers
1373                    .irq0_inte
1374                    .modify(IRQ0_INTE::SM2_TXNFULL.val(enabled as u32)),
1375                InterruptSources::Sm3TXNotFull => self
1376                    .registers
1377                    .irq0_inte
1378                    .modify(IRQ0_INTE::SM3_TXNFULL.val(enabled as u32)),
1379                InterruptSources::Sm0RXNotEmpty => self
1380                    .registers
1381                    .irq0_inte
1382                    .modify(IRQ0_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1383                InterruptSources::Sm1RXNotEmpty => self
1384                    .registers
1385                    .irq0_inte
1386                    .modify(IRQ0_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1387                InterruptSources::Sm2RXNotEmpty => self
1388                    .registers
1389                    .irq0_inte
1390                    .modify(IRQ0_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1391                InterruptSources::Sm3RXNotEmpty => self
1392                    .registers
1393                    .irq0_inte
1394                    .modify(IRQ0_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1395            }
1396        } else if irq_index == 1 {
1397            match interrupt_source {
1398                InterruptSources::Interrupt0 => self
1399                    .registers
1400                    .irq1_inte
1401                    .modify(IRQ1_INTE::SM0.val(enabled as u32)),
1402                InterruptSources::Interrupt1 => self
1403                    .registers
1404                    .irq1_inte
1405                    .modify(IRQ1_INTE::SM1.val(enabled as u32)),
1406                InterruptSources::Interrupt2 => self
1407                    .registers
1408                    .irq1_inte
1409                    .modify(IRQ1_INTE::SM2.val(enabled as u32)),
1410                InterruptSources::Interrupt3 => self
1411                    .registers
1412                    .irq1_inte
1413                    .modify(IRQ1_INTE::SM3.val(enabled as u32)),
1414                InterruptSources::Sm0TXNotFull => self
1415                    .registers
1416                    .irq1_inte
1417                    .modify(IRQ1_INTE::SM0_TXNFULL.val(enabled as u32)),
1418                InterruptSources::Sm1TXNotFull => self
1419                    .registers
1420                    .irq1_inte
1421                    .modify(IRQ1_INTE::SM1_TXNFULL.val(enabled as u32)),
1422                InterruptSources::Sm2TXNotFull => self
1423                    .registers
1424                    .irq1_inte
1425                    .modify(IRQ1_INTE::SM2_TXNFULL.val(enabled as u32)),
1426                InterruptSources::Sm3TXNotFull => self
1427                    .registers
1428                    .irq1_inte
1429                    .modify(IRQ1_INTE::SM3_TXNFULL.val(enabled as u32)),
1430                InterruptSources::Sm0RXNotEmpty => self
1431                    .registers
1432                    .irq1_inte
1433                    .modify(IRQ1_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1434                InterruptSources::Sm1RXNotEmpty => self
1435                    .registers
1436                    .irq1_inte
1437                    .modify(IRQ1_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1438                InterruptSources::Sm2RXNotEmpty => self
1439                    .registers
1440                    .irq1_inte
1441                    .modify(IRQ1_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1442                InterruptSources::Sm3RXNotEmpty => self
1443                    .registers
1444                    .irq1_inte
1445                    .modify(IRQ1_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1446            }
1447        } else {
1448            debug!("IRQ Index invalid - must be 0 or 1");
1449        }
1450    }
1451
1452    /// Checks if a PIO interrupt is set.
1453    pub fn interrupt_get(&self, irq_num: u32) -> bool {
1454        let mut temp = 0;
1455        match irq_num {
1456            0 => temp = self.registers.irq.read(IRQ::IRQ0),
1457            1 => temp = self.registers.irq.read(IRQ::IRQ1),
1458            2 => temp = self.registers.irq.read(IRQ::IRQ2),
1459            3 => temp = self.registers.irq.read(IRQ::IRQ3),
1460            4 => temp = self.registers.irq.read(IRQ::IRQ4),
1461            5 => temp = self.registers.irq.read(IRQ::IRQ5),
1462            6 => temp = self.registers.irq.read(IRQ::IRQ6),
1463            7 => temp = self.registers.irq.read(IRQ::IRQ7),
1464            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1465        }
1466        temp != 0
1467    }
1468
1469    /// Clear a PIO interrupt.
1470    pub fn interrupt_clear(&self, irq_num: u32) {
1471        match irq_num {
1472            0 => self.registers.irq.modify(IRQ::IRQ0.val(1)),
1473            1 => self.registers.irq.modify(IRQ::IRQ1.val(1)),
1474            2 => self.registers.irq.modify(IRQ::IRQ2.val(1)),
1475            3 => self.registers.irq.modify(IRQ::IRQ3.val(1)),
1476            4 => self.registers.irq.modify(IRQ::IRQ4.val(1)),
1477            5 => self.registers.irq.modify(IRQ::IRQ5.val(1)),
1478            6 => self.registers.irq.modify(IRQ::IRQ6.val(1)),
1479            7 => self.registers.irq.modify(IRQ::IRQ7.val(1)),
1480            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1481        }
1482    }
1483
1484    /// Handle interrupts
1485    pub fn handle_interrupt(&self) {
1486        let ints = &self.registers.irq0_ints;
1487        for (sm, irq) in self.sms.iter().zip([
1488            IRQ0_INTS::SM0_TXNFULL,
1489            IRQ0_INTS::SM1_TXNFULL,
1490            IRQ0_INTS::SM2_TXNFULL,
1491            IRQ0_INTS::SM3_TXNFULL,
1492        ]) {
1493            if ints.is_set(irq) {
1494                sm.handle_tx_interrupt();
1495            }
1496        }
1497        for (sm, irq) in self.sms.iter().zip([
1498            IRQ0_INTS::SM0_RXNEMPTY,
1499            IRQ0_INTS::SM1_RXNEMPTY,
1500            IRQ0_INTS::SM2_RXNEMPTY,
1501            IRQ0_INTS::SM3_RXNEMPTY,
1502        ]) {
1503            if ints.is_set(irq) {
1504                sm.handle_rx_interrupt();
1505            }
1506        }
1507    }
1508
1509    /// Adds a program to PIO.
1510    /// Call this with `add_program(Some(0), include_bytes!("path_to_file"))`.
1511    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1512    /// => program: the program to load into the PIO
1513    /// Returns `LoadedProgram` which contains information about program location and length.
1514    pub fn add_program(
1515        &self,
1516        origin: Option<usize>,
1517        program: &[u8],
1518    ) -> Result<LoadedProgram, ProgramError> {
1519        let mut program_u16: [u16; NUMBER_INSTR_MEMORY_LOCATIONS / 2] =
1520            [0; NUMBER_INSTR_MEMORY_LOCATIONS / 2];
1521        for (i, chunk) in program.chunks(2).enumerate() {
1522            program_u16[i] = ((chunk[0] as u16) << 8) | (chunk[1] as u16);
1523        }
1524
1525        self.add_program16(origin, &program_u16[0..program.len() / 2])
1526    }
1527
1528    /// Adds a program to PIO.
1529    /// Takes `&[u16]` as input, cause pio-asm operations are 16bit.
1530    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1531    /// => program: the program to load into the PIO
1532    /// Returns `LoadedProgram` which contains information about program location and size.
1533    pub fn add_program16(
1534        &self,
1535        origin: Option<usize>,
1536        program: &[u16],
1537    ) -> Result<LoadedProgram, ProgramError> {
1538        // if origin is not set, try naively to find an empty space
1539        match origin {
1540            Some(origin) => {
1541                assert!(origin < NUMBER_INSTR_MEMORY_LOCATIONS);
1542                self.try_load_program_at(origin, program)
1543                    .map_err(|_| ProgramError::AddrInUse(origin))
1544            }
1545            None => {
1546                for origin in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1547                    if let res @ Ok(_) = self.try_load_program_at(origin, program) {
1548                        return res;
1549                    }
1550                }
1551                Err(ProgramError::InsufficientSpace)
1552            }
1553        }
1554    }
1555
1556    /// Try to load program at a specific origin, relocate operations if necessary.
1557    /// Only for internals, use `add_program` or `add_program16` instead.
1558    /// => origin: the address in the PIO instruction memory to start the program at
1559    /// => program: the program to load into the PIO
1560    /// Returns Ok(()) if the program was loaded successfully, otherwise an error.
1561    fn try_load_program_at(
1562        &self,
1563        origin: usize,
1564        program: &[u16],
1565    ) -> Result<LoadedProgram, ProgramError> {
1566        // Relocate program
1567        let program = RelocatedProgram::new(program.iter(), origin);
1568        let mut used_mask = 0;
1569        for (i, instr) in program.enumerate() {
1570            // wrapping around the end of program memory is valid
1571            let addr = (i + origin) % 32;
1572            let mask = 1 << addr;
1573            if (self.instructions_used.get() | used_mask) & mask != 0 {
1574                return Err(ProgramError::AddrInUse(addr));
1575            }
1576            self.registers.instr_mem[addr]
1577                .instr_mem
1578                .modify(INSTR_MEMx::INSTR_MEM.val(instr as u32));
1579            used_mask |= mask;
1580        }
1581        // update the mask of used instructions slots
1582        self.instructions_used
1583            .set(self.instructions_used.get() | used_mask);
1584        Ok(LoadedProgram {
1585            used_memory: used_mask,
1586            origin,
1587        })
1588    }
1589
1590    /// Clears all of a PIO instance's instruction memory.
1591    pub fn clear_instr_registers(&self) {
1592        for i in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1593            self.registers.instr_mem[i]
1594                .instr_mem
1595                .modify(INSTR_MEMx::INSTR_MEM::CLEAR);
1596        }
1597
1598        // update the mask of used instructions slots
1599        self.instructions_used.set(0);
1600    }
1601
1602    /// Initialize a new PIO with the same default configuration for all four state machines.
1603    pub fn init(&self) {
1604        let default_config: StateMachineConfiguration = StateMachineConfiguration::default();
1605        for state_machine in self.sms.iter() {
1606            state_machine.config(&default_config);
1607        }
1608        self.clear_instr_registers()
1609    }
1610}
1611
1612mod examples {
1613    use super::{
1614        debug, Pio, RPGpio, RPGpioPin, Readable, SMNumber, SMx_EXECCTRL, SMx_INSTR, SMx_PINCTRL,
1615        StateMachineConfiguration, DBG_PADOUT, FDEBUG,
1616    };
1617
1618    impl RPGpio {
1619        fn from_u32(value: u32) -> RPGpio {
1620            match value {
1621                0 => RPGpio::GPIO0,
1622                1 => RPGpio::GPIO1,
1623                2 => RPGpio::GPIO2,
1624                3 => RPGpio::GPIO3,
1625                4 => RPGpio::GPIO4,
1626                5 => RPGpio::GPIO5,
1627                6 => RPGpio::GPIO6,
1628                7 => RPGpio::GPIO7,
1629                8 => RPGpio::GPIO8,
1630                9 => RPGpio::GPIO9,
1631                10 => RPGpio::GPIO10,
1632                11 => RPGpio::GPIO11,
1633                12 => RPGpio::GPIO12,
1634                13 => RPGpio::GPIO13,
1635                14 => RPGpio::GPIO14,
1636                15 => RPGpio::GPIO15,
1637                16 => RPGpio::GPIO16,
1638                17 => RPGpio::GPIO17,
1639                18 => RPGpio::GPIO18,
1640                19 => RPGpio::GPIO19,
1641                20 => RPGpio::GPIO20,
1642                21 => RPGpio::GPIO21,
1643                22 => RPGpio::GPIO22,
1644                23 => RPGpio::GPIO23,
1645                24 => RPGpio::GPIO24,
1646                25 => RPGpio::GPIO25,
1647                26 => RPGpio::GPIO26,
1648                27 => RPGpio::GPIO27,
1649                28 => RPGpio::GPIO28,
1650                29 => RPGpio::GPIO29,
1651                _ => panic!(
1652                    "Unknown value for GPIO pin: {} (should be from 0 to 29)",
1653                    value
1654                ),
1655            }
1656        }
1657    }
1658
1659    impl Pio {
1660        // # Examples
1661        /// Used for the examples in the pico explorer base main.rs file.
1662
1663        pub fn blinking_hello_program_init(
1664            &self,
1665            sm_number: SMNumber,
1666            pin: u32,
1667            config: &StateMachineConfiguration,
1668        ) {
1669            let sm = &self.sms[sm_number as usize];
1670            sm.config(config);
1671            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1672            sm.set_enabled(false);
1673            sm.set_pins_dirs(pin, 1, true);
1674            sm.set_set_pins(pin, 1);
1675            sm.init();
1676            sm.set_enabled(true);
1677        }
1678
1679        pub fn blink_program_init(
1680            &self,
1681            sm_number: SMNumber,
1682            pin: u32,
1683            config: &StateMachineConfiguration,
1684        ) {
1685            let sm = &self.sms[sm_number as usize];
1686            sm.config(config);
1687            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1688            sm.set_enabled(false);
1689            sm.set_pins_dirs(pin, 1, true);
1690            sm.set_set_pins(pin, 1);
1691            sm.init();
1692            sm.set_enabled(true);
1693        }
1694
1695        pub fn sideset_program_init(
1696            &self,
1697            sm_number: SMNumber,
1698            pin: u32,
1699            config: &StateMachineConfiguration,
1700        ) {
1701            let sm = &self.sms[sm_number as usize];
1702            sm.config(config);
1703            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1704            self.gpio_init(&RPGpioPin::new(RPGpio::GPIO7));
1705            sm.set_enabled(false);
1706            sm.set_pins_dirs(pin, 1, true);
1707            sm.set_pins_dirs(7, 1, true);
1708            sm.set_set_pins(pin, 1);
1709            sm.set_side_set_pins(7, 1, false, true);
1710            sm.init();
1711            sm.set_enabled(true);
1712        }
1713
1714        pub fn hello_program_init(
1715            &self,
1716            sm_number: SMNumber,
1717            pin1: u32,
1718            pin2: u32,
1719            config: &StateMachineConfiguration,
1720        ) {
1721            let sm = &self.sms[sm_number as usize];
1722            // This is used to turn on specifically GPIOs 6 and 7 - LSB is for GPIO 0, next bit is for GPIO 1 etc.
1723            let turn_on_gpio_6_7 = 0b11000000;
1724            sm.config(config);
1725            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin1)));
1726            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin2)));
1727            sm.set_enabled(false);
1728            sm.set_pins_dirs(pin1, 1, true);
1729            sm.set_pins_dirs(pin2, 1, true);
1730            sm.init();
1731            sm.set_enabled(true);
1732            sm.push_blocking(turn_on_gpio_6_7).ok();
1733            sm.push_blocking(0).ok();
1734        }
1735
1736        pub fn pwm_program_init(
1737            &self,
1738            sm_number: SMNumber,
1739            pin: u32,
1740            pwm_period: u32,
1741            config: &StateMachineConfiguration,
1742        ) {
1743            let sm = &self.sms[sm_number as usize];
1744            // "pull" command created by pioasm
1745            let pull_command = 0x8080_u16;
1746            // "out isr, 32" command created by pioasm
1747            let out_isr_32_command = 0x60c0_u16;
1748            sm.config(config);
1749            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1750            sm.set_enabled(false);
1751            sm.set_pins_dirs(pin, 1, true);
1752            sm.set_side_set_pins(pin, 1, false, true);
1753            sm.init();
1754            sm.push_blocking(pwm_period).ok();
1755            sm.exec(pull_command);
1756            sm.exec(out_isr_32_command);
1757            sm.set_enabled(true);
1758        }
1759
1760        pub fn spi_program_init(
1761            &self,
1762            sm_number: SMNumber,
1763            clock_pin: u32,
1764            in_pin: u32,
1765            out_pin: u32,
1766            config: &StateMachineConfiguration,
1767        ) {
1768            let sm = &self.sms[sm_number as usize];
1769            sm.config(config);
1770            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(clock_pin)));
1771            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(in_pin)));
1772            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(out_pin)));
1773            sm.set_enabled(false);
1774
1775            // Important: make the sideset pin an output pin then make it a side set pin
1776            // and make sure to do all of this BEFORE setting the outpin as an outpin
1777            sm.set_out_pins(clock_pin, 1);
1778            sm.set_pins_dirs(clock_pin, 1, true);
1779            sm.set_side_set_pins(clock_pin, 1, false, false); // Do not switch pin dirs again, it will mess with the output settings
1780
1781            sm.set_pins_dirs(out_pin, 1, true);
1782            sm.set_out_pins(out_pin, config.out_pins_count);
1783
1784            sm.init();
1785            sm.clear_fifos();
1786            sm.set_enabled(true);
1787        }
1788
1789        // # Debugging
1790        /// Returns current instruction running on the state machine.
1791        pub fn read_instr(&self, sm_number: SMNumber) -> u32 {
1792            self.registers.sm[sm_number as usize]
1793                .instr
1794                .read(SMx_INSTR::INSTR)
1795        }
1796
1797        pub fn read_sideset_reg(&self, sm_number: SMNumber) {
1798            debug!(
1799                "{}",
1800                self.registers.sm[sm_number as usize]
1801                    .pinctrl
1802                    .read(SMx_PINCTRL::SIDESET_COUNT)
1803            );
1804            debug!(
1805                "{}",
1806                self.registers.sm[sm_number as usize]
1807                    .execctrl
1808                    .read(SMx_EXECCTRL::SIDE_EN)
1809            );
1810            debug!(
1811                "{}",
1812                self.registers.sm[sm_number as usize]
1813                    .execctrl
1814                    .read(SMx_EXECCTRL::SIDE_PINDIR)
1815            );
1816            debug!(
1817                "{}",
1818                self.registers.sm[sm_number as usize]
1819                    .pinctrl
1820                    .read(SMx_PINCTRL::SIDESET_BASE)
1821            );
1822        }
1823
1824        pub fn read_dbg_padout(&self) -> u32 {
1825            self.registers.dbg_padout.read(DBG_PADOUT::DBG_PADOUT)
1826        }
1827
1828        pub fn read_fdebug(&self, tx: bool, stall: bool) -> u32 {
1829            if tx {
1830                if stall {
1831                    self.registers.fdebug.read(FDEBUG::TXSTALL)
1832                } else {
1833                    self.registers.fdebug.read(FDEBUG::TXOVER)
1834                }
1835            } else if stall {
1836                self.registers.fdebug.read(FDEBUG::RXSTALL)
1837            } else {
1838                self.registers.fdebug.read(FDEBUG::RXUNDER)
1839            }
1840        }
1841    }
1842}