# pio_uart_rx_restart_test.py - 23.07.2022 # # UART Schnittstelle -> Receiver from machine import Pin, mem32 from rp2 import PIO, StateMachine, asm_pio import array as arr # --- Receiver ---------------------------------------------------------- # # Prüft das Startbit, das Stopbit und die nachfolgende Pause # jeweils 2x. Jedes Bit hat eine Länge von 9 Takten. # Die Datenbits werden jeweils 1x in der Bitmitte abgetastet. # Takt = Baud * 9 @asm_pio(in_shiftdir=PIO.SHIFT_RIGHT, fifo_join=PIO.JOIN_RX ) def uart_rx(): label("restart") mov(isr, null) # 1 Bei einem Fehler sicherheitshalber das ISR zurücksetzen wait(0, pin, 0) [1] # 2 Warten auf eine fallende Flanke label("start") wrap_target() set(y, 7) # 3 den Counter fpr die Bits setzen # Das Signal ist mindestens 4 Takte gesetzt jmp(pin, "restart") [6] # 4 - Fehler, wenn der Takt das Startbit nicht mehr low jmp(pin, "restart") [12] # 5 - Fehler, wenn der Takt das Startbit nicht mehr low label("next_bit") in_(pins, 1) [13] # 6 Den Pegel einlesen und nach jmp(y_dec, "next_bit") # 7 weiteren 15 Takten das nächste Bit einlesen jmp(pin, "stop_bit_1") # 8 Das Stopbit muss high, sein jmp("restart") # 9 wenn nicht gesetzt, dann ist das ein Fehler label("stop_bit_1") jmp(pin, "byte_end") # 10 Das Stopbit muss high sein, jmp("restart") # 11 wenn nicht gesetzt, dann ist das ein Fehler label("byte_end") push(block) # 12 die empfangenen Bits ins Fifo irq(rel(0)) [2] # 13 label("end_1") set(y, 4) # 14 Wartezeit nach dem Stopbit nach 'y' # wenn innerhalb dieser Zeit der Level nicht # azf gnd geht, dann ist die Übertragung beendet label("end_2") jmp(y_dec, "end_3") # 15 Zähler Wartezeit decrementieren jmp("read_end") # 16 label("end_3") # jmp(pin, "end_2") # 17 hier prüfen, ob eine fallende Flanke auftrat wrap() # wenn ja, dann das nächste Byte einlesen label("read_end") irq(rel(0)) # 18 den Interrupt auslösen jmp("restart") # 19 class UART_PIO_RX(object): def __init__(self, statemachine, rx_pin, buffer_size, baud=9600): self._rx = StateMachine(statemachine, uart_rx, in_base=Pin(rx_pin, Pin.IN, Pin.PULL_UP), jmp_pin=Pin(rx_pin, Pin.IN, Pin.PULL_UP), freq = baud * 15) self.rx_buffer = arr.array("B", [0] * buffer_size) self.rx_idx = 0 self.rx_ready = False self.rx_overflow = False self._rx.irq(self._irq_handler) self.statemachine = statemachine self.active(1) def _restart(self): # userdefined statemachine.restart() PIO_BASE = 0x5020_0000 if self.statemachine & 0x04: # PIO0 or PIO1 ? PIO_BASE = 0x5030_0000 sm = self.statemachine & 0x03 ctrl_reg = mem32[PIO_BASE] # read CTRL-Register # ctrl_reg |= (1 << sm) # enable Bit ctrl_reg |= (1 << sm) << 4 # restart Bit print(f"{ctrl_reg:08b}") mem32[PIO_BASE] = ctrl_reg # write CTRL-Register def active(self, state=1): state = 1 if state else 0 if state: ############################################ self._rx.restart() # nur 1 Statemachine funktioniert #self._restart() # 4 Statemachines funktioiern ############################################ while self._rx.rx_fifo(): print(self._rx.get(None, 24)) self._rx.active(state) def _irq_handler(self, _): # Bei jedem Interrupt wurde genau 1 Byte empfangen # oder das Ende der Übertragung signalisiert try: if self._rx.rx_fifo(): self.rx_buffer[self.rx_idx] = self._rx.get(None, 24) self.rx_idx += 1 else: self.rx_ready = True except IndexError: self.rx_overflow = True def ready(self): return self.rx_ready def get_buffer(self): # den Buffer als Referenz übergeben + Anzahl Bytes if self.rx_overflow: self.rx_overflow = False cnt = 0 else: cnt = self.rx_idx self.rx_idx = 0 self.rx_ready = False return (self.rx_buffer, cnt) if __name__ == "__main__": import time rx_1 = UART_PIO_RX(statemachine = 0, rx_pin = 15, buffer_size = 20) rx_2 = UART_PIO_RX(statemachine = 1, rx_pin = 14, buffer_size = 20) rx_3 = UART_PIO_RX(statemachine = 2, rx_pin = 13, buffer_size = 20) rx_4 = UART_PIO_RX(statemachine = 3, rx_pin = 12, buffer_size = 20) print("Waitng for data - ctrl-C to stop") try: while True: if rx_1.ready(): # siehe time.sleep(.1) print() print(rx_1.get_buffer()) print(rx_2.get_buffer()) print(rx_3.get_buffer()) print(rx_4.get_buffer()) except KeyboardInterrupt: pass rx_1.active(0) #rx_2.active(0) #rx_3.active(0) #rx_4.active(0) print("\ndone")