diff --git a/examples/pioasm_background_morse.py b/examples/pioasm_background_morse.py new file mode 100644 index 0000000..d6cdc89 --- /dev/null +++ b/examples/pioasm_background_morse.py @@ -0,0 +1,104 @@ +# SPDX-FileCopyrightText: 2022 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +"""Demonstrate background writing, including loop writing, with morse code. + +On any rp2040 board with board.LED, this will alternately send 'SOS' and 'TEST' +via the LED, demonstrating that Python code continues to run while the morse +code data is transmitted. Alternately, change one line below to make it send +'TEST' forever in a loop, again while Python code continues to run. + +The combination of "LED status" and duration is sent to the PIO as 16-bit number: +The top bit is 1 if the LED is turned on and 0 otherwise. The other 15 bits form a delay +value from 1 to 32767. A subset of the morse code 'alphabit' is created, with everthing +based on the 'DIT duration' of about 128ms (1MHz / 32 / 4000). + +https://en.wikipedia.org/wiki/Morse_code +""" + +import time +import array +from board import LED +from rp2pio import StateMachine +from adafruit_pioasm import Program + +# This program turns the LED on or off depending on the first bit of the value, +# then delays a length of time given by the next 15 bits of the value. +# By correctly choosing the durations, a message in morse code can be sent. +pio_code = Program( + """ + out x, 1 + mov pins, x + out x, 15 + busy_wait: + jmp x--, busy_wait [31] + """ +) + + +# The top bit of the command is the LED value, on or off +LED_ON = 0x8000 +LED_OFF = 0x0000 + +# The other 15 bits are a delay duration. +# It must be the case that 4 * DIT_DURATION < 32768 +DIT_DURATION = 4000 +DAH_DURATION = 3 * DIT_DURATION + +# Build up some elements of morse code, based on the wikipedia article. +DIT = array.array("H", [LED_ON | DIT_DURATION, LED_OFF | DIT_DURATION]) +DAH = array.array("H", [LED_ON | DAH_DURATION, LED_OFF | DIT_DURATION]) +# That is, two more DAH-length gaps for a total of three +LETTER_SPACE = array.array("H", [LED_OFF | (2 * DAH_DURATION)]) +# That is, four more DAH-length gaps (after a letter space) for a total of seven +WORD_SPACE = array.array("H", [LED_OFF | (4 * DIT_DURATION)]) + +# Letters and words can be created by concatenating ("+") the elements +E = DAH + LETTER_SPACE +O = DAH + DAH + DAH + LETTER_SPACE +S = DIT + DIT + DIT + LETTER_SPACE +T = DIT + LETTER_SPACE +SOS = S + O + S + WORD_SPACE +TEST = T + E + S + T + WORD_SPACE + +# 8 slots of the shortest possible led-off time +# A background write is 'complete' as soon as all data has been placed +# in the StateMachine's FIFO. This FIFO has either 4 or 8 entries. +# By adding 8 very short "led off" times, we can have our 'sm.writing' test +# tell us when the actual letter data has all been +FILLER = array.array("H", [LED_OFF | 1]) * 8 + +sm = StateMachine( + pio_code.assembled, + frequency=1_000_000, + first_out_pin=LED, + pull_threshold=16, + auto_pull=True, + out_shift_right=False, +) + +# To simply repeat 'TEST' forever, change to 'if True': +if False: # pylint: disable=using-constant-test + print("Sending out TEST forever", end="") + sm.background_write(loop=TEST) + while True: + print(end=".") + time.sleep(0.1) + +# But instead, let's alternate SOS and TEST, forever: + +while True: + for plain, morse in ( + ("SOS", SOS), + ("TEST", TEST), + ): + print(f"Sending out {plain}", end="") + sm.background_write(morse + FILLER) + while sm.writing: + print(end=".") + time.sleep(0.1) + print() + print("Message all sent to StateMachine") + time.sleep(1) + print()