Question with dual RXUART via pio on Pico
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Question with dual RXUART via pio on Pico

by adechiaro on Thu Apr 08, 2021 8:07 pm

Hello! I'm trying to leverage the example RXUART pio implementation on a Pico to pull in data from 2x PM2.5 sensors.

My example works fine for a single UART, but when I try 2 it seems there are some issues with timing or synchronization. Posting the question here, as I'm definitely new to the Pico and concept of PIO, seeing if anyone has some suggestions.

This code fails to find the header at the start, but it seems data is being captured at least somewhat correctly ('BM' is present, just not at the start). I could hack around this by shifting the array, but figured I'd see if there was something I was overlooking first.

Code: Select all | TOGGLE FULL SIZE
code.py output:
created uart <RXUART at board.GP2>
created uart <RXUART at board.GP4>
error decoding data:
Traceback (most recent call last):
  File "code.py", line 109, in <module>
  File "code.py", line 76, in __init__

Code: Select all | TOGGLE FULL SIZE
# SPDX-FileCopyrightText: 2021 Jeff Epler, written for Adafruit Industries
# SPDX-License-Identifier: MIT

import rp2pio
import adafruit_pioasm
import board
import time

from adafruit_binascii import hexlify, unhexlify

code = adafruit_pioasm.assemble(
.program uart_rx_mini
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
; with the correct timing.
; IN pin 0 is mapped to the GPIO used as UART RX.
; Autopush must be enabled, with a threshold of 8.
    wait 0 pin 0        ; Wait for start bit
    set x, 7 [10]       ; Preload bit counter, delay until eye of first data bit
bitloop:                ; Loop 8 times
    in pins, 1          ; Sample data
    jmp x-- bitloop [6] ; Each iteration is 8 cycles

class RXUART:
    def __init__(self, pin, baudrate=9600):
        self.pin = pin
        self.pio = rp2pio.StateMachine(
            frequency=8 * baudrate,
    def __str__(self):
        return '<RXUART at {0}>'.format(self.pin)

    def timeout(self):
        return 0

    def baudrate(self):
        return self.pio.frequency // 8

    def baudrate(self, frequency):
        self.pio.frequency = freqency * 8

    def in_waiting(self):
        return self.pio.in_waiting

    def read(self, n):
        b = bytearray(n)
        n = self.pio.readinto(b)
        return b[:n]

    def readinto(self, buf):
        return self.pio.readinto(n)

class InvalidDataError(Exception):

class PM25:
    def __init__(self, data):
        if data[0:2] != b'BM':
            print('error decoding data:')
            raise InvalidDataError
        self.pmStd1 = self.bytesConvert(data[4:6])
        self.pmStd25 = self.bytesConvert(data[6:8])
        self.pmStd10 = self.bytesConvert(data[8:10])
        self.pmEnv1= self.bytesConvert(data[10:12])
        self.pmEnv25 = self.bytesConvert(data[12:14])
        self.pmEnv10 = self.bytesConvert(data[14:16])
        self.part03u = self.bytesConvert(data[16:18])
        self.part05u = self.bytesConvert(data[18:20])
        self.part10u = self.bytesConvert(data[20:22])
        self.part25u = self.bytesConvert(data[22:24])
        self.part50u = self.bytesConvert(data[24:26])
        self.part100u = self.bytesConvert(data[26:28])

    def __str__(self):
        #eturn '<PM Std ug/m^3 1.0={0}, 2.5={1}, 10={2} atmos_env 1.0={3}, 2.5={4}, 10={5}>'.format(self.pmStd1, self.pmStd25, self.pmStd10, self.pmEnv1, self.pmEnv25, self.pmEnv10)
        return '<PM part count / 0.1L u0.3={0}, u0.5={1}, u1.0={2} u2.5={3}, u5.0={4}, u10={5}>'.format(self.part03u, self.part05u, self.part10u, self.part25u, self.part50u, self.part100u)

    def bytesConvert(cls, data):
        return (int(data[0]) << 8) + int(data[1])

pm1 = RXUART(board.GP2)
pm2 = RXUART(board.GP4)
print('created uart %s' % pm1)
print('created uart %s' % pm2)
start = time.time()
while True:
    data1 = pm1.read(32)
    data2 = pm2.read(32)
    pmData1 = PM25(data1)
    pmData2 = PM25(data2)
    time_since = time.time() - start
    if time_since > 5:
        start = time.time()
Posts: 8
Joined: Thu Jun 11, 2009 4:51 pm

Please be positive and constructive with your questions and comments.