diff --git a/adafruit_pioasm.py b/adafruit_pioasm.py index 824140f..96fb8dd 100644 --- a/adafruit_pioasm.py +++ b/adafruit_pioasm.py @@ -38,6 +38,7 @@ def assemble(text_program): labels = {} instructions = [] sideset_count = 0 + sideset_enable = 0 for line in text_program.split("\n"): line = line.strip() if not line: @@ -55,6 +56,7 @@ def assemble(text_program): pass elif line.startswith(".side_set"): sideset_count = int(line.split()[1]) + sideset_enable = 1 if "opt" in line else 0 elif line.endswith(":"): label = line[:-1] if label in labels: @@ -64,7 +66,7 @@ def assemble(text_program): # Only add as an instruction if the line isn't empty instructions.append(line) - max_delay = 2 ** (5 - sideset_count) - 1 + max_delay = 2 ** (5 - sideset_count - sideset_enable) - 1 assembled = [] for instruction in instructions: # print(instruction) @@ -76,10 +78,13 @@ def assemble(text_program): raise RuntimeError("Delay too long:", delay) instruction.pop() if len(instruction) > 1 and instruction[-2] == "side": + if sideset_count == 0: + raise RuntimeError("No side_set count set") sideset_value = int(instruction[-1]) if sideset_value > 2 ** sideset_count: raise RuntimeError("Sideset value too large") - delay |= sideset_value << (5 - sideset_count) + delay |= sideset_value << (5 - sideset_count - sideset_enable) + delay |= sideset_enable << 4 instruction.pop() instruction.pop() @@ -186,6 +191,6 @@ def assemble(text_program): else: raise RuntimeError("Unknown instruction:" + instruction[0]) assembled[-1] |= delay << 8 - # print(hex(assembled[-1])) + # print(bin(assembled[-1])) return array.array("H", assembled) diff --git a/examples/txuart.py b/examples/txuart.py new file mode 100644 index 0000000..e12b5ab --- /dev/null +++ b/examples/txuart.py @@ -0,0 +1,53 @@ +# SPDX-FileCopyrightText: 2021 Jeff Epler, written for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import rp2pio +import adafruit_pioasm + +code = adafruit_pioasm.assemble( + """ +.program uart_tx +.side_set 1 opt + +; An 8n1 UART transmit program. +; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. + + pull side 1 [7] ; Assert stop bit, or stall with line in idle state + set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks +bitloop: ; This loop will run 8 times (8n1 UART) + out pins, 1 ; Shift 1 bit from OSR to the first OUT pin + jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. + +""" +) + + +class TXUART: + def __init__(self, *, tx, baudrate=9600): + self.pio = rp2pio.StateMachine( + code, + first_out_pin=tx, + first_sideset_pin=tx, + frequency=8 * baudrate, + initial_sideset_pin_state=1, + initial_sideset_pin_direction=1, + initial_out_pin_state=1, + initial_out_pin_direction=1, + sideset_enable=True, + ) + + @property + def timeout(self): + return 0 + + @property + def baudrate(self): + return self.pio.frequency // 8 + + @baudrate.setter + def baudrate(self, frequency): + self.pio.frequency = frequency * 8 + + def write(self, buf): + return self.pio.write(buf) diff --git a/tests/testpioasm.py b/tests/testpioasm.py index 1e90923..a15d01c 100644 --- a/tests/testpioasm.py +++ b/tests/testpioasm.py @@ -44,6 +44,14 @@ def testNop(self): self.assertAssemblesTo(".side_set 1\nnop side 1", [0b101_10000_010_00_010]) self.assertAssemblesTo(".side_set 1\nnop side 1 [1]", [0b101_10001_010_00_010]) + def testSidesetOpt(self): + self.assertAssemblesTo(".side_set 1 opt\nnop side 1", [0b101_11000_010_00_010]) + self.assertAssemblesTo(".side_set 1 opt\nnop side 0", [0b101_10000_010_00_010]) + self.assertAssemblesTo( + ".side_set 1 opt\nnop side 0 [1]", [0b101_10001_010_00_010] + ) + self.assertAssemblesTo(".side_set 1 opt\nnop [1]", [0b101_00001_010_00_010]) + def testJmp(self): self.assertAssemblesTo("l:\njmp l", [0b000_00000_000_00000]) self.assertAssemblesTo("l:\njmp 7", [0b000_00000_000_00111])