0

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:
bytearray(b'\x00\x00\x00\x00\x00\x97\x00\x01\xf6BM\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\n\x00\x02\x00')
Traceback (most recent call last):
  File "code.py", line 109, in <module>
  File "code.py", line 76, in __init__
InvalidDataError:


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(
            code,
            first_in_pin=pin,
            frequency=8 * baudrate,
            auto_push=True,
            push_threshold=8,
        )
       
    def __str__(self):
        return '<RXUART at {0}>'.format(self.pin)

    @property
    def timeout(self):
        return 0

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

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

    @property
    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):
    pass


class PM25:
    def __init__(self, data):
        if data[0:2] != b'BM':
            print('error decoding data:')
            print(data)
            raise InvalidDataError
        #print(data)
        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)

    @classmethod
    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()
        print(pmData1)
        print(pmData2)


If I comment out the second UART and related code, it seems to work just fine:

Code: Select all | TOGGLE FULL SIZE
created uart <RXUART at board.GP2>
<PM part count / 0.1L u0.3=21, u0.5=7, u1.0=0 u2.5=0, u5.0=0, u10=0>
<PM part count / 0.1L u0.3=21, u0.5=7, u1.0=0 u2.5=0, u5.0=0, u10=0>
<PM part count / 0.1L u0.3=30, u0.5=10, u1.0=1 u2.5=0, u5.0=0, u10=0>
<PM part count / 0.1L u0.3=33, u0.5=11, u1.0=1 u2.5=0, u5.0=0, u10=0>
<PM part count / 0.1L u0.3=24, u0.5=7, u1.0=1 u2.5=0, u5.0=0, u10=0>
<PM part count / 0.1L u0.3=36, u0.5=11, u1.0=1 u2.5=0, u5.0=0, u10=0>
adechiaro
 
Posts: 8
Joined: Thu Jun 11, 2009 4:51 pm

Re: Question with dual RXUART via pio on Pico

by mikeysklar on Fri Apr 09, 2021 5:50 pm

Stupid question, but are you able to comment out the first UART and use the second one only? Just wanted to make sure that each UART was working indepently before getting into the details of your PIO configuration.

mikeysklar
 
Posts: 4559
Joined: Mon Aug 01, 2016 8:10 pm

Please be positive and constructive with your questions and comments.