summaryrefslogtreecommitdiffstatshomepage
path: root/docs/rp2
diff options
context:
space:
mode:
authorNitiKaur <nitikaur102@gmail.com>2021-07-07 02:40:32 +0530
committerDamien George <damien@micropython.org>2021-10-13 15:54:49 +1100
commitbaa5a76fc09855dd0899077c09d72ba5d8681442 (patch)
tree0efc5542c4b600f88ecd0f8605753d27eb444dd4 /docs/rp2
parentd42cba0d22cac812cc5a12f4670010b45932eafa (diff)
downloadmicropython-baa5a76fc09855dd0899077c09d72ba5d8681442.tar.gz
micropython-baa5a76fc09855dd0899077c09d72ba5d8681442.zip
docs/rp2: Add reference for PIO assembly instructions, and PIO tutorial.
Diffstat (limited to 'docs/rp2')
-rw-r--r--docs/rp2/tutorial/intro.rst5
-rw-r--r--docs/rp2/tutorial/pio.rst123
2 files changed, 128 insertions, 0 deletions
diff --git a/docs/rp2/tutorial/intro.rst b/docs/rp2/tutorial/intro.rst
index 5609ab3798..69c3e6b0a5 100644
--- a/docs/rp2/tutorial/intro.rst
+++ b/docs/rp2/tutorial/intro.rst
@@ -4,3 +4,8 @@ Getting started with MicroPython on the RP2xxx
==============================================
Let's get started!
+
+.. toctree::
+ :maxdepth: 1
+
+ pio.rst
diff --git a/docs/rp2/tutorial/pio.rst b/docs/rp2/tutorial/pio.rst
new file mode 100644
index 0000000000..9981aed832
--- /dev/null
+++ b/docs/rp2/tutorial/pio.rst
@@ -0,0 +1,123 @@
+Programmable IO
+===============
+
+The RP2040 has hardware support for standard communication protocols like I2C,
+SPI and UART. For protocols where there is no hardware support, or where there
+is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes
+into play. Also, some MicroPython applications make use of a technique called
+bit banging in which pins are rapidly turned on and off to transmit data. This
+can make the entire process slow as the processor concentrates on bit banging
+rather than executing other logic. However, PIO allows bit banging to happen
+in the background while the CPU is executing the main work.
+
+Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO
+blocks each of which has four independent state machines. These state machines
+can transfer data to/from other entities using First-In-First-Out (FIFO) buffers,
+which allow the state machine and main processor to work independently yet also
+synchronise their data. Each FIFO has four words (each of 32 bits) which can be
+linked to the DMA to transfer larger amounts of data.
+
+All PIO instructions follow a common pattern::
+
+ <instruction> .side(<side_set_value>) [<delay_value>]
+
+The side-set ``.side(...)`` and delay ``[...]`` parts are both optional, and if
+specified allow the instruction to perform more than one operation. This keeps
+PIO programs small and efficient.
+
+There are nine instructions which perform the following tasks:
+
+- ``jmp()`` transfers control to a different part of the code
+- ``wait()`` pauses until a particular action happens
+- ``in_()`` shifts the bits from a source (scratch register or set of pins) to the
+ input shift register
+- ``out()`` shifts the bits from the output shift register to a destination
+- ``push()`` sends data to the RX FIFO
+- ``pull()`` receives data from the TX FIFO
+- ``mov()`` moves data from a source to a destination
+- ``irq()`` sets or clears an IRQ flag
+- ``set()`` writes a literal value to a destination
+
+The instruction modifiers are:
+
+- ``.side()`` sets the side-set pins at the start of the instruction
+- ``[]`` delays for a certain number of cycles after execution of the instruction
+
+There are also directives:
+
+- ``wrap_target()`` specifies where the program execution will get continued from
+- ``wrap()`` specifies the instruction where the control flow of the program will
+ get wrapped from
+- ``label()`` sets a label for use with ``jmp()`` instructions
+- ``word()`` emits a raw 16-bit value which acts as an instruction in the program
+
+An example
+----------
+
+Take the ``pio_1hz.py`` example for a simple understanding of how to use the PIO
+and state machines. Below is the code for reference.
+
+.. code-block:: python3
+
+ # Example using PIO to blink an LED and raise an IRQ at 1Hz.
+
+ import time
+ from machine import Pin
+ import rp2
+
+
+ @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
+ def blink_1hz():
+ # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
+ irq(rel(0))
+ set(pins, 1)
+ set(x, 31) [5]
+ label("delay_high")
+ nop() [29]
+ jmp(x_dec, "delay_high")
+
+ # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
+ set(pins, 0)
+ set(x, 31) [6]
+ label("delay_low")
+ nop() [29]
+ jmp(x_dec, "delay_low")
+
+
+ # Create the StateMachine with the blink_1hz program, outputting on Pin(25).
+ sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
+
+ # Set the IRQ handler to print the millisecond timestamp.
+ sm.irq(lambda p: print(time.ticks_ms()))
+
+ # Start the StateMachine.
+ sm.active(1)
+
+This creates an instance of class :class:`rp2.StateMachine` which runs the
+``blink_1hz`` program at 2000Hz, and connects to pin 25. The ``blink_1hz``
+program uses the PIO to blink an LED connected to this pin at 1Hz, and also
+raises an IRQ as the LED turns on. This IRQ then calls the ``lambda`` function
+which prints out a millisecond timestamp.
+
+The ``blink_1hz`` program is a PIO assembler routine. It connects to a single
+pin which is configured as an output and starts out low. The instructions do
+the following:
+
+- ``irq(rel(0))`` raises the IRQ associated with the state machine.
+- The LED is turned on via the ``set(pins, 1)`` instruction.
+- The value 31 is put into register X, and then there is a delay for 5 more
+ cycles, specified by the ``[5]``.
+- The ``nop() [29]`` instruction waits for 30 cycles.
+- The ``jmp(x_dec, "delay_high")`` will keep looping to the ``delay_high`` label
+ as long as the register X is non-zero, and will also post-decrement X. Since
+ X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]``
+ runs 32 times in total (note there is also one instruction cycle taken by the
+ ``jmp`` for each of these 32 loops).
+- ``set(pins, 0)`` will turn the LED off by setting pin 25 low.
+- Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute.
+- Because ``wrap_target()`` and ``wrap()`` are not specified, their default will
+ be used and execution of the program will wrap around from the bottom to the
+ top. This wrapping does not cost any execution cycles.
+
+The entire routine takes exactly 2000 cycles of the state machine. Setting the
+frequency of the state machine to 2000Hz makes the LED blink at 1Hz.