Matrix Portal Hangs

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Matrix Portal Hangs

Post by adafruitguy »

I have a pair of Matrix Portals and SCD-30 CO2 Sensors, I have configured them using the RGB Matrix Portal Room CO2 Monitor example https://learn.adafruit.com/matrix-porta ... nsor-setup, without the cool enclosure. The code stops running / freezes without any errors, and the Matrix Portal becomes unavailable (spinning beach ball) as a CIRCUITPY drive until resetting.

I have also added print statements to see where it's hanging, and it seems like it is hanging at any point in the example code.

I have also added WiFi connected adafruit.io examples to upload the co2, temp, and humidity measurements and also experience cases of random hangs (without errors) on the Cortex M4, yet the ESP32 co-processor remains responsive on the WiFi network to pings.
Hardware Setup
Hardware Setup
IMG_3393.jpeg (423.71 KiB) Viewed 302 times
Both Matrix Portals are running the same Bootloader

Code: Select all

UF2 Bootloader v1.23.1-adafruit.1-328-gf06693a SFHWRO
Model: Matrix Portal M4
Board-ID: SAMD51J19A-MatrixPortal-v0
I have tried ESP Firmware versions 1.2.2 and 1.7.3

Code: Select all

Firmware vers. bytearray(b'1.2.2\x00')
ESP Firmware Version: bytearray(b'1.7.3\x00')
Various CircuitPython versions...

Code: Select all

Adafruit CircuitPython 6.0.0-rc.0 on 2020-10-16; Adafruit Matrix Portal M4 with samd51j19
Adafruit CircuitPython 6.0.0 on 2020-11-16; Adafruit Matrix Portal M4 with samd51j19
Adafruit CircuitPython 6.1.0 on 2021-01-21; Adafruit Matrix Portal M4 with samd51j19
Adafruit CircuitPython 6.2.0 on 2021-04-05; Adafruit Matrix Portal M4 with samd51j19
Adafruit CircuitPython 7.0.0-alpha.1-164-g01979acd4 on 2021-04-20; Adafruit Matrix Portal M4 with samd51j19
And, Library Bundle: adafruit-circuitpython-bundle-6.x-mpy-20210417

In addition to the code from the RGB Matrix Portal Room CO2 Monitor example, I have tried code with the addition of Adafruit IO uploads, using http and mqtt.

Matrix Portal 1 HTTP feed example

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# adafruit_circuitpython_adafruitio usage with an esp32spi_socket
# Matrix Portal 001 Example http feed: co2, temp, rh

import time
from random import randint
import board
import displayio
import busio
from digitalio import DigitalInOut
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_requests as requests
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
import adafruit_imageload
from adafruit_matrixportal.matrix import Matrix
import adafruit_scd30

# --| User Config |----
CO2_CUTOFFS = (1000, 2000, 5000)
UPDATE_RATE = 10
# ---------------------

# the sensor
scd30 = adafruit_scd30.SCD30(board.I2C())

# optional if known (pick one)
# scd30.ambient_pressure = 1013.25
# scd30.altitude = 0

# the display
matrix = Matrix(width=64, height=32, bit_depth=6)
display = matrix.display
#display.rotation = 90  # matrixportal up
display.rotation = 270 # matrixportal down

# current condition smiley face
smileys_bmp, smileys_pal = adafruit_imageload.load("/bmps/smileys.bmp")
smiley = displayio.TileGrid(
    smileys_bmp,
    pixel_shader=smileys_pal,
    x=0,
    y=0,
    width=1,
    height=1,
    tile_width=32,
    tile_height=32,
)

# current condition label
tags_bmp, tags_pal = adafruit_imageload.load("/bmps/tags.bmp")
label = displayio.TileGrid(
    tags_bmp,
    pixel_shader=tags_pal,
    x=0,
    y=32,
    width=1,
    height=1,
    tile_width=32,
    tile_height=16,
)

# current CO2 value
digits_bmp, digits_pal = adafruit_imageload.load("/bmps/digits.bmp")
co2_value = displayio.TileGrid(
    digits_bmp,
    pixel_shader=digits_pal,
    x=0,
    y=51,
    width=4,
    height=1,
    tile_width=8,
    tile_height=10,
)

# put em all together
splash = displayio.Group()
splash.append(smiley)
splash.append(label)
splash.append(co2_value)

# and show em
display.show(splash)


def update_display(value):

    value = abs(round(value))

    # smiley and label
    if value < CO2_CUTOFFS[0]:
        smiley[0] = label[0] = 0
    elif value < CO2_CUTOFFS[1]:
        smiley[0] = label[0] = 1
    elif value < CO2_CUTOFFS[2]:
        smiley[0] = label[0] = 2
    else:
        smiley[0] = label[0] = 3

    # CO2 value
    # clear it
    for i in range(4):
        co2_value[i] = 10
    # update it
    i = 3
    while value:
        co2_value[i] = value % 10
        value = int(value / 10)
        i -= 1

# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

# If you have an externally connected ESP32:
# esp32_cs = DigitalInOut(board.D9)
# esp32_ready = DigitalInOut(board.D10)
# esp32_reset = DigitalInOut(board.D5)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except RuntimeError as e:
        print("could not connect to AP, retrying: ", e)
        continue
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)

socket.set_interface(esp)
requests.set_socket(socket, esp)

# Set your Adafruit IO Username and Key in secrets.py
# (visit io.adafruit.com if you need to create an account,
# or if you need your Adafruit IO key.)
aio_username = secrets["aio_username"]
aio_key = secrets["aio_key"]

# Initialize an Adafruit IO HTTP API object
io = IO_HTTP(aio_username, aio_key, requests)

try:
    # Get the 'co2' feed from Adafruit IO
    co2_feed = io.get_feed("mp1-co2")
except AdafruitIO_RequestError:
    # If no 'co2' feed exists, create one
    co2_feed = io.create_new_feed("mp1-co2")

try:
    # Get the 'temp' feed from Adafruit IO
    temp_feed = io.get_feed("mp1-temp")
except AdafruitIO_RequestError:
    # If no 'temp' feed exists, create one
    temp_feed = io.create_new_feed("mp1-temp")

try:
    # Get the 'rh' feed from Adafruit IO
    rh_feed = io.get_feed("mp1-rh")
except AdafruitIO_RequestError:
    # If no 'rh' feed exists, create one
    rh_feed = io.create_new_feed("mp1-rh")

while True:
    print("hello")
#    print("Firmware vers.", esp.firmware_version)
        # protect against NaNs and Nones
#    try:
    data_is_go = scd30.data_available
    if data_is_go:
        print("Data Available!")
        co2_read = scd30.CO2
        temp_read = scd30.temperature
        rh_read = scd30.relative_humidity
        print("Read Complete!")
        temp_F = temp_read * 1.8 + 32
        print("Sending {0} to display...".format(co2_read))
        update_display(co2_read)
        print("Display complete!")
        print("Sending {0} to co2 feed...".format(co2_read))
        io.send_data(co2_feed["key"], co2_read)
        print("Sending {0} to temp feed...".format(temp_F))
        io.send_data(temp_feed["key"], temp_F)
        print("Sending {0} to rh feed...".format(rh_read))
        io.send_data(rh_feed["key"], rh_read)
        print("Data Sent!")
#    except:
#        pass
    print("Waiting {0}...".format(UPDATE_RATE))
    time.sleep(UPDATE_RATE)
Matrix Portal 1 HTTP output (small) example, no hangs

Code: Select all

Connected to {WiFi Networks Name} 	RSSI: -31
hello
Firmware vers. bytearray(b'1.7.3\x00')
Data Available!
Read Complete!
Sending 477.056 to display...
Display complete!
Sending 477.056 to co2 feed...
Sending 71.1359 to temp feed...
Sending 34.0454 to rh feed...
Data Sent!
Waiting 10...
Matrix Portal 2 MQTT feed example

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# Matrix Portal 002 Example mqtt feed: co2, temp, rh, and onoff message reads

import time
import board
import busio
from digitalio import DigitalInOut
import neopixel
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket

import adafruit_minimqtt.adafruit_minimqtt as MQTT
import adafruit_scd30
import adafruit_imageload
import displayio
from adafruit_matrixportal.matrix import Matrix

# --| User Config |----
CO2_CUTOFFS = (1000, 2000, 5000)
UPDATE_RATE = 10
# ---------------------

# the sensor
scd30 = adafruit_scd30.SCD30(board.I2C())


# optional if known (pick one)
# scd30.ambient_pressure = 1013.25
# scd30.altitude = 0

# the display
matrix = Matrix(width=64, height=32, bit_depth=6)
display = matrix.display
# display.rotation = 90  # matrixportal up
display.rotation = 270 # matrixportal down


# current condition smiley face
smileys_bmp, smileys_pal = adafruit_imageload.load("/bmps/smileys.bmp")
smiley = displayio.TileGrid(
    smileys_bmp,
    pixel_shader=smileys_pal,
    x=0,
    y=0,
    width=1,
    height=1,
    tile_width=32,
    tile_height=32,
)

# current condition label
tags_bmp, tags_pal = adafruit_imageload.load("/bmps/tags.bmp")
label = displayio.TileGrid(
    tags_bmp,
    pixel_shader=tags_pal,
    x=0,
    y=32,
    width=1,
    height=1,
    tile_width=32,
    tile_height=16,
)

# current CO2 value
digits_bmp, digits_pal = adafruit_imageload.load("/bmps/digits.bmp")
co2_value = displayio.TileGrid(
    digits_bmp,
    pixel_shader=digits_pal,
    x=0,
    y=51,
    width=4,
    height=1,
    tile_width=8,
    tile_height=10,
)

# put em all together
splash = displayio.Group()
splash.append(smiley)
splash.append(label)
splash.append(co2_value)

# and show em
display.show(splash)


def update_display(value):

    value = abs(round(value))

    # smiley and label
    if value < CO2_CUTOFFS[0]:
        smiley[0] = label[0] = 0
    elif value < CO2_CUTOFFS[1]:
        smiley[0] = label[0] = 1
    elif value < CO2_CUTOFFS[2]:
        smiley[0] = label[0] = 2
    else:
        smiley[0] = label[0] = 3

    # CO2 value
    # clear it
    for i in range(4):
        co2_value[i] = 10
    # update it
    i = 3
    while value:
        co2_value[i] = value % 10
        value = int(value / 10)
        i -= 1

### WiFi ###

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

# If you have an externally connected ESP32:
# esp32_cs = DigitalInOut(board.D9)
# esp32_ready = DigitalInOut(board.D10)
# esp32_reset = DigitalInOut(board.D5)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
"""Use below for Most Boards"""
status_light = neopixel.NeoPixel(
    board.NEOPIXEL, 1, brightness=0.2
)  # Uncomment for Most Boards
"""Uncomment below for ItsyBitsy M4"""
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
# Uncomment below for an externally defined RGB LED
# import adafruit_rgbled
# from adafruit_esp32spi import PWMOut
# RED_LED = PWMOut.PWMOut(esp, 26)
# GREEN_LED = PWMOut.PWMOut(esp, 27)
# BLUE_LED = PWMOut.PWMOut(esp, 25)
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)

### Feeds ###

# Setup a adafruit io feeds for publishing
co2_feed = secrets["aio_username"] + "/feeds/mp2-co2"
temp_feed = secrets["aio_username"] + "/feeds/mp2-temp"
rh_feed = secrets["aio_username"] + "/feeds/mp2-rh"

# Setup a feed named 'onoff' for subscribing to changes
onoff_feed = secrets["aio_username"] + "/feeds/mp2-onoff"

### Code ###

# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connected(client, userdata, flags, rc):
    # This function will be called when the client is connected
    # successfully to the broker.
    print("Connected to Adafruit IO! Listening for topic changes on %s" % onoff_feed)
    # Subscribe to all changes on the onoff_feed.
    client.subscribe(onoff_feed)


def disconnected(client, userdata, rc):
    # This method is called when the client is disconnected
    print("Disconnected from Adafruit IO!")


def message(client, topic, message):
    # This method is called when a topic the client is subscribed to
    # has a new message.
    print("New message on topic {0}: {1}".format(topic, message))


# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected!")

# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)

# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
    broker="io.adafruit.com",
    username=secrets["aio_username"],
    password=secrets["aio_key"],
)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print("Connecting to Adafruit IO...")
mqtt_client.connect()


while True:
    print("hello")
    # Poll the message queue
    mqtt_client.loop()
    # See of scd30 is ready to read
    data_is_go = scd30.data_available
    if data_is_go:
        print("Data Available!")
        co2_reading = scd30.CO2
        temp_reading = scd30.temperature
        rh_reading = scd30.relative_humidity
        print("Read Complete!")
        temp_F = temp_reading * 1.8 + 32
        print("Sending {0} to display...".format(co2_reading))
        update_display(co2_reading)
        print("Display complete!")
        print("Sending co2 value: {0}...".format(co2_reading))
        mqtt_client.publish(co2_feed, co2_reading)
        print("Sending temp value: {0}...".format(temp_F))
        mqtt_client.publish(temp_feed, temp_F)
        print("Sending rh value: {0}...".format(rh_reading))
        mqtt_client.publish(rh_feed, rh_reading)
        print("Send Complete!")
    print("Waiting %d..." % UPDATE_RATE)
    time.sleep(UPDATE_RATE)
Matrix Portal 2 MQTT output (small) example, no hangs

Code: Select all

hello
Data Available!
Read Complete!
Sending 660.055 to display...
Display complete!
Sending co2 value: 660.055...
Sending temp value: 70.9533...
Sending rh value: 36.9202...
Send Complete!
Waiting 10...
hello
Data Available!
Read Complete!
Sending 660.068 to display...
Display complete!
Sending co2 value: 660.068...
Sending temp value: 71.0013...
Sending rh value: 36.6913...
Send Complete!
Waiting 10...
hello
Data Available!
Read Complete!
Sending 661.549 to display...
Display complete!
Sending co2 value: 661.549...
Sending temp value: 71.0782...
Sending rh value: 36.9278...
Send Complete!
Waiting 10...
hello
Data Available!
Read Complete!
Sending 662.537 to display...
Display complete!
Sending co2 value: 662.537...
Sending temp value: 71.1023...
Sending rh value: 36.7813...
Send Complete!
Waiting 10...
During hangs, the M4 is always unresponsive, but the ESP32 always appears to remain active on WiFi and responsive to pings

Code: Select all

jeremy@WOPR ~ % ping 192.168.4.164
PING 192.168.4.164 (192.168.4.164): 56 data bytes
64 bytes from 192.168.4.164: icmp_seq=0 ttl=255 time=88.963 ms
64 bytes from 192.168.4.164: icmp_seq=1 ttl=255 time=90.206 ms
64 bytes from 192.168.4.164: icmp_seq=2 ttl=255 time=11.470 ms
64 bytes from 192.168.4.164: icmp_seq=3 ttl=255 time=31.201 ms
64 bytes from 192.168.4.164: icmp_seq=4 ttl=255 time=56.376 ms
64 bytes from 192.168.4.164: icmp_seq=5 ttl=255 time=77.759 ms
64 bytes from 192.168.4.164: icmp_seq=6 ttl=255 time=98.783 ms
64 bytes from 192.168.4.164: icmp_seq=7 ttl=255 time=117.541 ms
64 bytes from 192.168.4.164: icmp_seq=8 ttl=255 time=35.827 ms

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

You're seeing this same behavior with both setups?

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

Yes, both setups.

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

The code stops running / freezes without any errors, and the Matrix Portal becomes unavailable (spinning beach ball) as a CIRCUITPY drive until resetting.
Are you powering the entire setup from a PC's USB port?

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

Power is via: USB Type A to Type C Cables (Product ID: 4474).

When connected for serial monitoring or programing: One (1) setup per MacBook Pro.

Otherwise:

Adafruit 5V 2A Switching Power Supply w/ USB-A Connector (Product ID: 1994)
or Extech 1-30VDC 20A Adjustable Power Supply w/ Multifunction Basic Power Supply Test Line - Banana to Various (Product ID: 3523)

Each setup up maxes out ~1.4A
Extech 1-30VDC 20A Adjustable Power Supply
Extech 1-30VDC 20A Adjustable Power Supply
IMG_1887.jpeg (274.21 KiB) Viewed 284 times

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

So when running off that bench supply, you determine it's freezing by the RGB matrix just no longer updating?

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

RGB matrix remains static with the last reading indefinitely, and there is no response to a 'breath test' in the vicinity of the CO2 sensor.

Also, when using the Adafruit IO examples, it stops uploading data.

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

Weird. That power should be plenty. Try with the basic example from the Matrix Portal library:
https://github.com/adafruit/Adafruit_Ci ... pletest.py
and see if you get the same behavior. So ignore the SCD30 and AdafruitIO for now.

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

As suggested running simple test....

(Note: I removed the symbol for the British Currency from this code example, as it is apparently a "banned spam word" as is the official name of said currency, and replaced with "P" for forum posting)...

Code: Select all

# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams, written for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
This example checks the current BANNED price and displays it in the middle of the screen
"""
import time
import board
import terminalio
from adafruit_matrixportal.matrixportal import MatrixPortal

# You can display in 'GBP', 'EUR' or 'USD'
CURRENCY = "USD"
# Set up where we'll be fetching data from
DATA_SOURCE = "https://api.coindesk.com/v1/bpi/currentprice.json"
DATA_LOCATION = ["bpi", CURRENCY, "rate_float"]


def text_transform(val):
    if CURRENCY == "USD":
        return "$%d" % val
    if CURRENCY == "EUR":
        return "‎€%d" % val
    if CURRENCY == "GBP":
        return "P%d" % val
    return "%d" % val


# the current working directory (where this file is)
cwd = ("/" + __file__).rsplit("/", 1)[0]

matrixportal = MatrixPortal(
    url=DATA_SOURCE,
    json_path=DATA_LOCATION,
    status_neopixel=board.NEOPIXEL,
)

matrixportal.add_text(
    text_font=terminalio.FONT,
    text_position=(16, 16),
    text_color=0xFFFFFF,
    text_transform=text_transform,
)
matrixportal.preload_font(b"$012345789")  # preload numbers
matrixportal.preload_font((0x00A3, 0x20AC))  # preload gbp/euro symbol

while True:
    try:
        value = matrixportal.fetch()
        print("Response is", value)
    except (ValueError, RuntimeError) as e:
        print("Some error occured, retrying! -", e)

    time.sleep(3 * 60)  # wait 3 minutes
Added the following libraries...
  • adafruit_portalbase
    adafruit_bitmap_font
    adafruit_display_text
    adafruit_fakerequests
    neopixel.mpy
Power draw is much less ~0.3-0.5A

Will monitor, as hangs can sometime take some time.
Simpletest Example
Simpletest Example
IMG_1900.jpeg (506.57 KiB) Viewed 259 times

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

Simpletest Example continues to run on my unit #1 without halting, it's a record uptime, I will let it continue.
Simple Test - Still Running, over 20 hours.
Simple Test - Still Running, over 20 hours.
IMG_1901.jpeg (548.81 KiB) Viewed 237 times
I have upgraded the bootloader on my Matrix Portal #2. While this is not listed on the circuitpython.org Matrix Portal page, I found it on GitHub.

Code: Select all

UF2 Bootloader v3.13.0 SFHWRO
Model: Matrix Portal M4
Board-ID: SAMD51J19A-MatrixPortal-v0
And, #2 is running the following....

Code: Select all

# Write your code here :-)
import time
import board
import displayio
import adafruit_imageload
from adafruit_matrixportal.matrix import Matrix
import adafruit_scd30

# --| User Config |----
CO2_CUTOFFS = (1000, 2000, 5000)
UPDATE_RATE = 1
# ---------------------

# the sensor
scd30 = adafruit_scd30.SCD30(board.I2C())

# optional if known (pick one)
# scd30.ambient_pressure = 1013.25
# scd30.altitude = 0

# the display
matrix = Matrix(width=64, height=32, bit_depth=6)
display = matrix.display
display.rotation = 90  # matrixportal up
# display.rotation = 270 # matrixportal down

# current condition smiley face
smileys_bmp, smileys_pal = adafruit_imageload.load("/bmps/smileys.bmp")
smiley = displayio.TileGrid(
    smileys_bmp,
    pixel_shader=smileys_pal,
    x=0,
    y=0,
    width=1,
    height=1,
    tile_width=32,
    tile_height=32,
)

# current condition label
tags_bmp, tags_pal = adafruit_imageload.load("/bmps/tags.bmp")
label = displayio.TileGrid(
    tags_bmp,
    pixel_shader=tags_pal,
    x=0,
    y=32,
    width=1,
    height=1,
    tile_width=32,
    tile_height=16,
)

# current CO2 value
digits_bmp, digits_pal = adafruit_imageload.load("/bmps/digits.bmp")
co2_value = displayio.TileGrid(
    digits_bmp,
    pixel_shader=digits_pal,
    x=0,
    y=51,
    width=4,
    height=1,
    tile_width=8,
    tile_height=10,
)

# put em all together
splash = displayio.Group()
splash.append(smiley)
splash.append(label)
splash.append(co2_value)

# and show em
display.show(splash)


def update_display(value):

    value = abs(round(value))

    # smiley and label
    if value < CO2_CUTOFFS[0]:
        smiley[0] = label[0] = 0
        print("Good... {0}".format(value))
    elif value < CO2_CUTOFFS[1]:
        smiley[0] = label[0] = 1
        print("Poor... {0}".format(value))
    elif value < CO2_CUTOFFS[2]:
        smiley[0] = label[0] = 2
        print("Warning... {0}".format(value))
    else:
        smiley[0] = label[0] = 3
        print("Danger... {0}".format(value))

    # CO2 value
    # clear it
    for i in range(4):
        co2_value[i] = 10
    # update it
    i = 3
    while value:
        co2_value[i] = value % 10
        value = int(value / 10)
        i -= 1

run_count = 0

while True:
    # protect against NaNs and Nones
    try:
        update_display(scd30.CO2)
    except:
        pass
    run_count += 1
    print("Run Count... {0}".format(run_count))
    time.sleep(UPDATE_RATE)
Example Output...

Code: Select all

Good... 630
Run Count... 1
Good... 630
Run Count... 2
Good... 630
Run Count... 3
Good... 630
Run Count... 4
Good... 630
Run Count... 5
Good... 631
Run Count... 6
Good... 631
Run Count... 7
Good... 632
Run Count... 8
. . .
Are there any other system level debugging things that I can add to the code to look at resources / etc, perhaps to see what might be causing the M4 to halt?

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

Are there any other system level debugging things that I can add to the code to look at resources / etc, perhaps to see what might be causing the M4 to halt?
First step would be try and isolate the specific line of code that it is halting on. Can do that by simply adding more print statements, which can be an interactive process. Once the specific line is found, can drill in further. If it's a library call, would need to start looking at library code.

At this point the tests are just trying to determine if it might network related, etc.

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

The simple test (BANNED) on my Matrix Portal #1 continues to run. Day two... no hangs.

The stripped down (no read / write calls to Adafruit IO) example on Matrix Portal #2 with CO2 reads (my last post), has been running without hanging, for a day, and since I upgraded the bootloader.

The network honestly should be good. I have ~18 devices talking to Adafruit IO that are rock solid. JP’s Network Connected RGB Matrix Clock is my only CircuitPython example besides this CO2 exercise. The rest are Arduino based code.

My IO Plus subscription rate is for 120 / minute. I average <40 / minute - so I should have adequate headroom, and hopefully the CircuitPython calls would give an error instead of just hanging.

For the CO2 exercise I tried both MQTT and HTTP examples. I would see the M4 hang during Adafruit IO write calls (without errors), and occasionally on Matrix Display writes.

I will boot up the MQTT example again, with more print statements.....

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import busio
from digitalio import DigitalInOut
import neopixel
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket

import adafruit_minimqtt.adafruit_minimqtt as MQTT
import adafruit_scd30
import adafruit_imageload
import displayio
from adafruit_matrixportal.matrix import Matrix

# --| User Config |----
CO2_CUTOFFS = (1000, 2000, 5000)
UPDATE_RATE = 10
# ---------------------

# the sensor
scd30 = adafruit_scd30.SCD30(board.I2C())


# optional if known (pick one)
# scd30.ambient_pressure = 1013.25
# scd30.altitude = 0

# the display
matrix = Matrix(width=64, height=32, bit_depth=6)
display = matrix.display
# display.rotation = 90  # matrixportal up
display.rotation = 270 # matrixportal down


# current condition smiley face
smileys_bmp, smileys_pal = adafruit_imageload.load("/bmps/smileys.bmp")
smiley = displayio.TileGrid(
    smileys_bmp,
    pixel_shader=smileys_pal,
    x=0,
    y=0,
    width=1,
    height=1,
    tile_width=32,
    tile_height=32,
)

# current condition label
tags_bmp, tags_pal = adafruit_imageload.load("/bmps/tags.bmp")
label = displayio.TileGrid(
    tags_bmp,
    pixel_shader=tags_pal,
    x=0,
    y=32,
    width=1,
    height=1,
    tile_width=32,
    tile_height=16,
)

# current CO2 value
digits_bmp, digits_pal = adafruit_imageload.load("/bmps/digits.bmp")
co2_value = displayio.TileGrid(
    digits_bmp,
    pixel_shader=digits_pal,
    x=0,
    y=51,
    width=4,
    height=1,
    tile_width=8,
    tile_height=10,
)

# put em all together
splash = displayio.Group()
splash.append(smiley)
splash.append(label)
splash.append(co2_value)

# and show em
display.show(splash)


def update_display(value):

    value = abs(round(value))

    # smiley and label
    if value < CO2_CUTOFFS[0]:
        smiley[0] = label[0] = 0
        print("Display: Good... {0}".format(value))
    elif value < CO2_CUTOFFS[1]:
        smiley[0] = label[0] = 1
        print("Display: Poor... {0}".format(value))
    elif value < CO2_CUTOFFS[2]:
        smiley[0] = label[0] = 2
        print("Display: Warning... {0}".format(value))
    else:
        smiley[0] = label[0] = 3
        print("Display: Danger... {0}".format(value))

    # CO2 value
    # clear it
    for i in range(4):
        co2_value[i] = 10
    # update it
    i = 3
    while value:
        co2_value[i] = value % 10
        value = int(value / 10)
        i -= 1

### WiFi ###

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

# If you have an externally connected ESP32:
# esp32_cs = DigitalInOut(board.D9)
# esp32_ready = DigitalInOut(board.D10)
# esp32_reset = DigitalInOut(board.D5)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
"""Use below for Most Boards"""
status_light = neopixel.NeoPixel(
    board.NEOPIXEL, 1, brightness=0.2
)  # Uncomment for Most Boards
"""Uncomment below for ItsyBitsy M4"""
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
# Uncomment below for an externally defined RGB LED
# import adafruit_rgbled
# from adafruit_esp32spi import PWMOut
# RED_LED = PWMOut.PWMOut(esp, 26)
# GREEN_LED = PWMOut.PWMOut(esp, 27)
# BLUE_LED = PWMOut.PWMOut(esp, 25)
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)

### Feeds ###

# Setup a adafruit io feeds for publishing
co2_feed = secrets["aio_username"] + "/feeds/mp2-co2"
temp_feed = secrets["aio_username"] + "/feeds/mp2-temp"
rh_feed = secrets["aio_username"] + "/feeds/mp2-rh"

# Setup a feed named 'onoff' for subscribing to changes
onoff_feed = secrets["aio_username"] + "/feeds/mp2-onoff"

### Code ###

# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connected(client, userdata, flags, rc):
    # This function will be called when the client is connected
    # successfully to the broker.
    print("Connected to Adafruit IO! Listening for topic changes on %s" % onoff_feed)
    # Subscribe to all changes on the onoff_feed.
    client.subscribe(onoff_feed)


def disconnected(client, userdata, rc):
    # This method is called when the client is disconnected
    print("Disconnected from Adafruit IO!")


def message(client, topic, message):
    # This method is called when a topic the client is subscribed to
    # has a new message.
    print("New message on topic {0}: {1}".format(topic, message))


# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected!")

# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)

# Set up a MiniMQTT Client
mqtt_client = MQTT.MQTT(
    broker="io.adafruit.com",
    username=secrets["aio_username"],
    password=secrets["aio_key"],
)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print("Connecting to Adafruit IO...")
mqtt_client.connect()

run_count = 0

while True:
    print("hello")
    # Poll the message queue
    try:
        mqtt_client.loop()
    except:
        print("Poll Message Error!")
        pass
    # See of scd30 is ready to read
    data_is_go = scd30.data_available
    if data_is_go:
        print("Data Available!")
        try:
            co2_reading = scd30.CO2
        except:
            print("CO2 Sensor Read Error!")
            pass
        try:
            temp_reading = scd30.temperature
        except:
            print("Temp Sensor Read Error!")
            pass
        try:
            rh_reading = scd30.relative_humidity
        except:
            print("RH Sensor Read Error!")
            pass
        print("Read Complete!")
        temp_F = temp_reading * 1.8 + 32
        print("Sending {0} to display...".format(co2_reading))
        try:
            update_display(co2_reading)
            print("Display complete!")
        except:
            print("Display Update Error!")
            pass
        print("Sending co2 value: {0}...".format(co2_reading))
        try:
            mqtt_client.publish(co2_feed, co2_reading)
        except:
            print("CO2 IO Publish Error!")
            pass
        print("Sending temp value: {0}...".format(temp_F))
        try:
            mqtt_client.publish(temp_feed, temp_F)
        except:
            print("Temp IO Publish Error!")
            pass
        print("Sending rh value: {0}...".format(rh_reading))
        try:
            mqtt_client.publish(rh_feed, rh_reading)
        except:
            print("RH IO Publish Error!")
            pass
        print("Send Complete!")
    run_count += 1
    print("Run Count... {0}".format(run_count))
    print("Waiting %d..." % UPDATE_RATE)
    time.sleep(UPDATE_RATE)
Here's a start, we'll see how it goes....

Code: Select all

code.py output:
Connecting to WiFi...
Connected!
Connecting to Adafruit IO...
Connected to Adafruit IO! Listening for topic changes on {aio_username}/feeds/mp2-onoff
hello
Data Available!
Read Complete!
Sending 840.918 to display...
Display: Good... 841
Display complete!
Sending co2 value: 840.918...
Sending temp value: 72.9288...
Sending rh value: 35.556...
Send Complete!
Run Count... 1
Waiting 10...
hello
Data Available!
Read Complete!
Sending 834.94 to display...
Display: Good... 835
Display complete!
Sending co2 value: 834.94...
Sending temp value: 72.8759...
Sending rh value: 35.4553...
Send Complete!
Run Count... 2
Waiting 10...
hello
Data Available!
Read Complete!
Sending 827.063 to display...
Display: Good... 827
Display complete!
Sending co2 value: 827.063...
Sending temp value: 72.8038...
Sending rh value: 35.5087...
Send Complete!
Run Count... 3
Waiting 10...
hello
Data Available!
Read Complete!
Sending 819.76 to display...
Display: Good... 820
Display complete!
Sending co2 value: 819.76...
Sending temp value: 72.8038...
Sending rh value: 35.5087...
Send Complete!
Run Count... 4
Waiting 10...
hello
Data Available!
Read Complete!
Sending 807.801 to display...
Display: Good... 808
Display complete!
Sending co2 value: 807.801...
Sending temp value: 72.8519...
Sending rh value: 35.5774...
Send Complete!
Run Count... 5
Waiting 10...
hello
Data Available!
Read Complete!
Sending 802.509 to display...
Display: Good... 803
Display complete!
Sending co2 value: 802.509...
Sending temp value: 72.8519...
Sending rh value: 35.5377...
Send Complete!
Run Count... 6
Waiting 10...
hello
Data Available!
Read Complete!
Sending 789.879 to display...
Display: Good... 790
Display complete!
Sending co2 value: 789.879...
Sending temp value: 72.8519...
Sending rh value: 35.524...
Send Complete!
Run Count... 7
Waiting 10...
hello
Data Available!
Read Complete!
Sending 788.086 to display...
Display: Good... 788
Display complete!
Sending co2 value: 788.086...
Sending temp value: 72.8759...
Sending rh value: 35.4996...
Send Complete!
Run Count... 8
Waiting 10...

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

MQTT Example, after about an hour, hung sending co2 reading to Adafruit IO.
  • - Display still showing the last reading value,
    - CO2 sensor LED suggests the sensor is continuing to take regular samples (orange LED throb),
    - ESP32 Wi-Fi coprocessor still responding to pings on local network,
    - No errors observed on Adafruit IO, usage never exceeded 40 of 120 subscribed rate.

Code: Select all

print("Sending co2 value: {0}...".format(co2_reading))
        try:
            mqtt_client.publish(co2_feed, co2_reading)
        except:
            print("CO2 IO Publish Error!")
            pass
LAST OUTPUT
-------
hello
Data Available!
Read Complete!
Sending 798.238 to display...
Display: Good... 798
Display complete!
Sending co2 value: 798.238...
Sending temp value: 73.5056...
Sending rh value: 35.1624...
Send Complete!
Run Count... 369
Waiting 10...
hello
Data Available!
Read Complete!
Sending 798.495 to display...
Display: Good... 798
Display complete!
Sending co2 value: 798.495...

User avatar
adafruit_support_carter
 
Posts: 29056
Joined: Tue Nov 29, 2016 2:45 pm

Re: Matrix Portal Hangs

Post by adafruit_support_carter »

Thanks. Good work narrowing down where exactly it was hanging. So seems to be something in the call to publish(). There are few loops where things could potentially get trapped:
https://github.com/adafruit/Adafruit_Ci ... tt.py#L556

I'd suggest opening a new issue for this in the repo. I can do that for you if you don't have a Github account.

User avatar
adafruitguy
 
Posts: 206
Joined: Sat Jun 07, 2014 7:52 am

Re: Matrix Portal Hangs

Post by adafruitguy »

I have reported issue #81 "Getting trapped in publish?".

I am also able to reproduce similar behavior with HTTP (io.send_data)....

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# adafruit_circuitpython_adafruitio usage with an esp32spi_socket
import time
from random import randint
import board
import displayio
import busio
from digitalio import DigitalInOut
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
import adafruit_requests as requests
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
import adafruit_imageload
from adafruit_matrixportal.matrix import Matrix
import adafruit_scd30

# --| User Config |----
CO2_CUTOFFS = (1000, 2000, 5000)
UPDATE_RATE = 10
# ---------------------

# the sensor
scd30 = adafruit_scd30.SCD30(board.I2C())

# optional if known (pick one)
# scd30.ambient_pressure = 1013.25
# scd30.altitude = 0

# the display
matrix = Matrix(width=64, height=32, bit_depth=6)
display = matrix.display
#display.rotation = 90  # matrixportal up
display.rotation = 270 # matrixportal down

# current condition smiley face
smileys_bmp, smileys_pal = adafruit_imageload.load("/bmps/smileys.bmp")
smiley = displayio.TileGrid(
    smileys_bmp,
    pixel_shader=smileys_pal,
    x=0,
    y=0,
    width=1,
    height=1,
    tile_width=32,
    tile_height=32,
)

# current condition label
tags_bmp, tags_pal = adafruit_imageload.load("/bmps/tags.bmp")
label = displayio.TileGrid(
    tags_bmp,
    pixel_shader=tags_pal,
    x=0,
    y=32,
    width=1,
    height=1,
    tile_width=32,
    tile_height=16,
)

# current CO2 value
digits_bmp, digits_pal = adafruit_imageload.load("/bmps/digits.bmp")
co2_value = displayio.TileGrid(
    digits_bmp,
    pixel_shader=digits_pal,
    x=0,
    y=51,
    width=4,
    height=1,
    tile_width=8,
    tile_height=10,
)

# put em all together
splash = displayio.Group()
splash.append(smiley)
splash.append(label)
splash.append(co2_value)

# and show em
display.show(splash)


def update_display(value):

    value = abs(round(value))

    # smiley and label
    if value < CO2_CUTOFFS[0]:
        smiley[0] = label[0] = 0
        print("Display: Good... {0}".format(value))
    elif value < CO2_CUTOFFS[1]:
        smiley[0] = label[0] = 1
        print("Display: Poor... {0}".format(value))
    elif value < CO2_CUTOFFS[2]:
        smiley[0] = label[0] = 2
        print("Display: Warning... {0}".format(value))
    else:
        smiley[0] = label[0] = 3
        print("Display: Danger... {0}".format(value))

    # CO2 value
    # clear it
    for i in range(4):
        co2_value[i] = 10
    # update it
    i = 3
    while value:
        co2_value[i] = value % 10
        value = int(value / 10)
        i -= 1

# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

# If you have an externally connected ESP32:
# esp32_cs = DigitalInOut(board.D9)
# esp32_ready = DigitalInOut(board.D10)
# esp32_reset = DigitalInOut(board.D5)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except RuntimeError as e:
        print("could not connect to AP, retrying: ", e)
        continue
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)

socket.set_interface(esp)
requests.set_socket(socket, esp)

# Set your Adafruit IO Username and Key in secrets.py
# (visit io.adafruit.com if you need to create an account,
# or if you need your Adafruit IO key.)
aio_username = secrets["aio_username"]
aio_key = secrets["aio_key"]

# Initialize an Adafruit IO HTTP API object
io = IO_HTTP(aio_username, aio_key, requests)

try:
    # Get the 'co2' feed from Adafruit IO
    co2_feed = io.get_feed("mp1-co2")
except AdafruitIO_RequestError:
    # If no 'co2' feed exists, create one
    co2_feed = io.create_new_feed("mp1-co2")

try:
    # Get the 'temp' feed from Adafruit IO
    temp_feed = io.get_feed("mp1-temp")
except AdafruitIO_RequestError:
    # If no 'temp' feed exists, create one
    temp_feed = io.create_new_feed("mp1-temp")

try:
    # Get the 'rh' feed from Adafruit IO
    rh_feed = io.get_feed("mp1-rh")
except AdafruitIO_RequestError:
    # If no 'rh' feed exists, create one
    rh_feed = io.create_new_feed("mp1-rh")

run_count = 0

while True:
    print("hello")
#    print("Firmware vers.", esp.firmware_version)
        # protect against NaNs and Nones
#    try:
    data_is_go = scd30.data_available
    if data_is_go:
        print("Data Available!")
        try:
            co2_read = scd30.CO2
        except:
            print("CO2 Sensor Read Error!")
            pass
        try:
            temp_read = scd30.temperature
        except:
            print("Temp Sensor Read Error!")
            pass
        try:
            rh_read = scd30.relative_humidity
        except:
            print("RH Sensor Read Error!")
            pass
        print("Sensor Reads Complete!")
        temp_F = temp_read * 1.8 + 32
        try:
            print("Sending {0} to display...".format(co2_read))
            update_display(co2_read)
        except:
            print("Display Update Error!")
            pass
        print("Display complete!")
        try:
            print("Sending {0} to co2 feed...".format(co2_read))
            io.send_data(co2_feed["key"], co2_read)
        except:
            print("CO2 IO Publish Error!")
            pass
        try:
            print("Sending {0} to temp feed...".format(temp_F))
            io.send_data(temp_feed["key"], temp_F)
        except:
            print("Temp IO Publish Error!")
            pass
        try:
            print("Sending {0} to rh feed...".format(rh_read))
            io.send_data(rh_feed["key"], rh_read)
        except:
            print("RH IO Publish Error!")
            pass
        print("Data Sent!")
#    except:
#        pass
    run_count += 1
    print("Run Count... {0}".format(run_count))
    print("Waiting {0}...".format(UPDATE_RATE))
    time.sleep(UPDATE_RATE)
Similar to my previous MQTT example, but here it is stalling and not recovering at io.send_data, this example was after 2+ hours, and exhibited the same behaviors...
  • - Display still showing the last reading value,
    - CO2 sensor LED suggests the sensor is continuing to take regular samples (orange LED throb),
    - ESP32 Wi-Fi coprocessor still responding to pings on local network,
    - No errors observed on Adafruit IO, usage never exceeded 40 of 120 subscribed rate.

Code: Select all

        try:
            print("Sending {0} to rh feed...".format(rh_read))
            io.send_data(rh_feed["key"], rh_read)
OUTPUT
-----
. . .
hello
Data Available!
Read Complete!
Sending 681.12 to display...
Display: Good... 681
Display complete!
Sending 681.12 to co2 feed...
Sending 75.2552 to temp feed...
Sending 34.288 to rh feed...
Data Sent!
Run Count... 853
Waiting 10...
hello
Data Available!
Read Complete!
Sending 681.182 to display...
Display: Good... 681
Display complete!
Sending 681.182 to co2 feed...
Sending 75.2311 to temp feed...
Sending 34.2743 to rh feed...

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”