adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4k stars 1.18k forks source link

7.0.0 crashes without import microcontroller #5469

Closed b-blake closed 2 years ago

b-blake commented 2 years ago

CircuitPython version

Adafruit CircuitPython 7.0.0 on 2021-09-20; Raspberry Pi Pico with rp2040
Board ID:raspberry_pi_pico
boot.py output:
    Write to Flash  : False
    Write to SD Card: True
    boot.py Finis

Code/REPL

No erreo code given when it crashes.  Must push reset or remove power.

Behavior

Crash without 'import microcontroller' even though not used. Runs just fine with 'import microcontroller'

Description

I built an application that would take in an RCA IR code of 'change input' and put out 7 'skip 30 seconds' TiVo IR codes. The application was working fine. I wanted to find out how to reference a pin that is not defined by CircuitPython but is on the RP2040. I used 'import microcontroller' to test how to define a pin using 'from microcontroller import pin' then 'test = pin.GPIO6'. It worked fine. I have commented out lines 2 and 3 of the test code. and things work fine. If I comment out the first test line (import microcontroller) the program crashes within the 'import adafruit_irremote' library after iteration #4 of 7 each time. microcontroller is not referenced in my code or in adafruit_irremote.py code. Below is my code that works/doesn't work minus the libraries. There are no error codes displayed on REPL. The only way out is a hard reset with the reset button or pulling power. Ctrl-C has no effect.

Additional information

No response

b-blake commented 2 years ago
    IR Relay and translate by B.B.Blake 10/10/2021
import board
import digitalio
from   digitalio import DigitalInOut, Direction, Pull
import neopixel
import pulseio
import pwmio
import time
import microcontroller
#from   microcontroller import pin
#test = pin.GPIO6

import adafruit_esp32spi
from   adafruit_esp32spi import PWMOut
import adafruit_irremote

Pico  = False
Itsy  = False
bd    = board.board_id
print("\f" + bd, end=" ")
if(bd == "adafruit_itsybitsy_rp2040"):
    Itsy = True
if(bd == "raspberry_pi_pico"):
    Pico = True
while(Pico == Itsy):
    print("Board Not Supported.")
    time.sleep(15)
    pass
print("Board Supported.")

if(Pico == True):
    IR_RX            = board.GP2  # Pin connected to  IR receiver.
    time.sleep(0.1)
    IR_PWR           = board.GP1
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True
    time.sleep(0.1)

    IR_TX            = board.GP26
    #IR_TX            = DigitalInOut(IR_TX)
    #IR_TX.direction  = Direction.OUTPUT
    #IR_TX.value      = True
    time.sleep(0.1)

    R_LED            = DigitalInOut(board.GP6)
    R_LED.direction  = Direction.OUTPUT
    B_LED            = DigitalInOut(board.GP7)
    B_LED.direction  = Direction.OUTPUT
    G_LED            = DigitalInOut(board.GP8)
    G_LED.direction  = Direction.OUTPUT

    LED            = DigitalInOut(board.LED)
    LED.direction  = Direction.OUTPUT
    time.sleep(0.1)

if(Itsy == True):
    IR_RX            = board.RX  # Pin connected to  IR receiver.
    time.sleep(0.1)
    IR_PWR           = board.D5
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True
    time.sleep(0.1)

    RED   = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE  = (0, 0, 255)
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)

    IR_TX            = board.TX
    #IR_TX            = DigitalInOut(IR_TX)
    #IR_TX.direction  = Direction.OUTPUT
    #IR_TX.value      = True
    time.sleep(0.1)
    PIXEL_PIN1       = board.D7      # NeoPixel #1
    PIXELS_NUM1      = 1             # NeoPixel #1
    PIXEL_BRIGHT1    = 0.25          # NeoPixel #1
    PIXEL_ORDER1     = neopixel.RGB  # NeoPixel #1    (In, +5, Gnd, Out]-flat side to Right [RGB]
    status_light1    = neopixel.NeoPixel(PIXEL_PIN1, PIXELS_NUM1, brightness=PIXEL_BRIGHT1, auto_write=True,  pixel_order=PIXEL_ORDER1)
    status_light1[0] = WHITE

    LED              = DigitalInOut(board.LED)
    LED.direction    = Direction.OUTPUT

    NeoPix           = DigitalInOut(board.NEOPIXEL)
    NeoPix.direction = Direction.OUTPUT

    time.sleep(0.1)

freq = 38000
duty = 32768

# Fuzzy pulse comparison function:
def fuzzy_pulse_compare(pulse1, pulse2, fuzzyness=0.2):
    if(Pico): R_LED.value, G_LED.value, B_LED.value = False, False, False
    if(Itsy): status_light1.fill(BLACK)
    print(len(pulse1), len(pulse2))
    if len(pulse1) != len(pulse2):
        print("Pulse Lengths don't match.")
        if(Pico): B_LED.value = True
        if(Itsy): status_light1.fill(BLUE)
        return False
    for i in range(len(pulse1)):
        threshold = (int(pulse1[i]) * fuzzyness)
        if abs(pulse1[i] - pulse2[i]) > threshold:
            print(abs(pulse1[i] - pulse2[i]), i)
            if(Pico): R_LED.value = True
            if(Itsy): status_light1.fill(RED)
            return False
    if(Pico): G_LED.value = True
    if(Itsy): status_light1.fill(GREEN)
    return True

# Expected pulse, pasted in from previous recording REPL session:
START1 = 9500
START2 = 4500
BEGIN  =  562 # Begin  Value header
ZERO   =  562 # 562.5, 562.5,
ONE    = 1687 # 562.5, 1687.5,
STOP   =  562 # trail
SKIP30x = ([0xD0, 0x27, 0x30, 0x85])
SKIP30y = ([0xD0, 0x27, 0x30, 0x85])
SKIP30 = [9500, 4500, # Skip 30 0xD0273085
        562, 1687,  562,  562,  562, 1687,  562,  562,  562,  562,  562,  562,  562,  562,  562, 1687, # 85
        562,  562,  562,  562,  562,  562,  562,  562,  562, 1687,  562, 1687,  562,  562,  562,  562, # 30
        562, 1687,  562, 1687,  562, 1687,  562,  562,  562,  562,  562, 1687,  562,  562,  562,  562, # 27
        562,  562,  562,  562,  562,  562,  562,  562,  562, 1687,  562,  562,  562, 1687,  562, 1687, # D0
        562]
INPUTx = ([0x40, 0xBF, 0xFB, 0x04])
INPUTy = ([0x40, 0xBF, 0xFB, 0x04])
INPUT = [9500, 4500, # Input 0x40BFFB04
        562,  562,  562,  562,  562, 1687,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562, # 04
        562, 1687,  562, 1687,  562,  562,  562, 1687,  562, 1687,  562, 1687,  562, 1687,  562, 1687, # FB
        562, 1687,  562, 1687,  562,  562,  562, 1687,  562,  562,  562,  562,  562,  562,  562,  562, # BF
        562,  562,  562,  562,  562, 1687,  562,  562,  562, 1687,  562, 1687,  562, 1687,  562, 1687, # 40
        562]
OKx   = ([0xE3, 0x1C, 0xFF, 0x00])
OKy   = ([0xE3, 0x1C, 0xFF, 0x00])
OK    = [9500, 4500, # OK 0xE31CFFOO
        562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562,  562, # 00
        562, 1687,  562, 1687,  562, 1687,  562, 1687,  562, 1687,  562, 1687,  562, 1687,  562, 1687, # FF
        562,  562,  562,  562,  562, 1687,  562, 1687,  562, 1687,  562,  562,  562,  562,  562,  562, # 1C
        562, 1687,  562, 1687,  562,  562,  562,  562,  562,  562,  562, 1687,  562, 1687,  562, 1687, # E3
        562]

# Create pulse INPUT and IR decoder.
pulses  = pulseio.PulseIn(IR_RX, maxlen=200, idle_state=True)
#pulseout = pulseio.PulseOut(IR_TX, frequency=freq, duty_cycle=duty) Duplicate
decoder = adafruit_irremote.GenericDecode()

# Create a 'pwmio' OUTPUT, to send infrared signals on the IR transmitter @ 38KHz
pwm = pwmio.PWMOut(IR_TX, frequency=freq, duty_cycle=duty)
pulseout = pulseio.PulseOut(pwm)
# Create an encoder that will take numbers and turn them into NEC IR pulses
encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], zero=[562,  562], one=[562, 1687], trail=562, debug=False)
#encoder = adafruit_irremote.GenericTransmit((9500, 4500), (562, 1687), (562, 562), 562)
print("#"*80)

#detected = encoder.transmit(pulseout, OK)
#Send_IR_Code(OK)
ion = False
while ion:
    time.sleep(0.3)
    pulses.clear()
    time.sleep(0.4)
    pulses.resume()
    time.sleep(0.3)
    pulse1 = decoder.read_pulses(pulses)
    print("IR Code Received")
    print(len(pulse1))
    print(pulse1)
    print("#"*80)

while not ion:
    time.sleep(0.3)
    pulses.clear()
    time.sleep(0.4)
    pulses.resume()
    time.sleep(0.3)
    # Loop waiting to receive pulses.
    while True:
        print('IR listener started...')
        # Wait for an IR Code to be detected.
        detected = decoder.read_pulses(pulses)
        time.sleep(.001)
#        print(detected)
        print('got an IR Code...')
        # Got an IR Code, now compare.
        if fuzzy_pulse_compare(INPUT, detected, 0.5):
            LED.value = True
            print('Received correct INPUT remote control press!')
            for xx in range(7):
                print(7-xx, end=" ")
                Kz = [0,0,0,0]
                SKIP30y = ([0xD0, 0x27, 0x30, 0x85])
                Ky = SKIP30y
#                print(Ky)
                for y in range(8): # Reverse the bits, Not sure why.
                    for x in range(4):
                        Bit     = (Ky[x] & 1)
#                        print(Bit, end="")
                        Ky[x]   = (Ky[x] >> 1)
                        Kz[3-x] = ((Kz[3-x] << 1) + Bit)
#                    print(" ", end="")
                IR_Command = (Kz)     
                encoder.transmit(pulseout, IR_Command, nbits=32)
                time.sleep(0.5)
            LED.value = False
            print("")
            pulses.clear()
            time.sleep(0.4)
            pulses.resume()
            time.sleep(0.5)
        elif fuzzy_pulse_compare(OK, detected, 0.5):
            print('Received correct OK remote control press!')
        elif fuzzy_pulse_compare(SKIP30, detected, 0.5):
            print('Received correct SKIP30 remote control press!')
        print("#"*80)

'''
>>> import board
>>> dir(board)
['__class__', '__name__', 'A0', 'A1', 'A2', 'A3',
'GP0',  'GP1',  'GP2',  'GP3',  'GP4',  'GP5',  'GP6',  'GP7',  'GP8',  'GP9',
'GP10', 'GP11', 'GP12', 'GP13', 'GP14', 'GP15', 'GP16', 'GP17', 'GP18', 'GP19',
'GP20', 'GP21', 'GP22', 'GP23', 'GP24', 'GP25',
'GP26', 'GP26_A0', 'GP27', 'GP27_A1', 'GP28', 'GP28_A2',
'LED', 'SMPS_MODE', 'VBUS_SENSE', 'VOLTAGE_MONITOR', 'board_id']
>>>
>>> import supervisor
>>> dir(supervisor)
['__class__', '__name__', 'RunReason', 'disable_autoreload', 'enable_autoreload',
'disable_ble_workflow', 'get_previous_traceback', 'reload', 'runtime',
'set_next_code_file', 'set_next_stack_limit', 'set_rgb_status_brightness', 'ticks_ms']
>>>
>>> import microcontroller
>>> dir(microcontroller)
['__class__', '__name__', 'Pin', 'Processor', 'ResetReason', 'RunMode',
'cpu', 'cpus', 'delay_us', 'disable_interrupts', 'enable_interrupts',
'nvm', 'on_next_reset', 'pin', 'reset', 'watchdog']
>>>
>>> import microcontroller
>>> dir(microcontroller.pin)
['__class__', 'GPIO0', 'GPIO1', 'GPIO2', 'GPIO3', 'GPIO4', 'GPIO5', 'GPIO6', 'GPIO7', 'GPIO8', 'GPIO9',
'GPIO10', 'GPIO11', 'GPIO12', 'GPIO13', 'GPIO14', 'GPIO15', 'GPIO16', 'GPIO17', 'GPIO18', 'GPIO19',
'GPIO20', 'GPIO21', 'GPIO22', 'GPIO23', 'GPIO24', 'GPIO25', 'GPIO26', 'GPIO27', 'GPIO28', 'GPIO29']
>>>
>>> help("modules")
__main__             bitops                math                  sdcardio
_bleio               board                 microcontroller       sharpdisplay
adafruit_bus_device  builtins              micropython           storage
adafruit_pixelbuf    busio                 msgpack               struct
aesio                collections           neopixel_write        supervisor
alarm                countio               onewireio             synthio
analogio             digitalio             os                    sys
array                displayio             pulseio               terminalio
atexit               errno                 pwmio                 time
audiobusio           fontio                qrio                  touchio
audiocore            framebufferio         rainbowio             traceback
audiomixer           gc                    random                ulab
audiomp3             getpass               re                    usb_cdc
audiopwmio           imagecapture          rgbmatrix             usb_hid
binascii             io                    rotaryio              usb_midi
bitbangio            json                  rp2pio                vectorio
bitmaptools          keypad                rtc                   watchdog
               Plus any modules on the filesystem
>>>
jepler commented 2 years ago

Looks like you have a boot.py file. Please attach its content in case it is relevant.

b-blake commented 2 years ago

Jepler,

Below is my boot.py file. The result is not used. The pin to determine what action to take is changed board to board to avoid conflict. I get the same results when I remove boot.py. Pin A3 is unused on the ItsyBitsy.

###########################################
"""CircuitPython Essentials Storage logging boot.py file"""
import board
from digitalio import DigitalInOut, Direction, Pull
import storage

# For Feather M0/M4 Express, RPi Pico, etc.
switch           = DigitalInOut(board.A3)
switch.direction = Direction.INPUT
switch.pull      = Pull.UP

# If the switch pin is connected to ground CircuitPython can write to the root drive
storage.remount("/", switch.value)
print("\tWrite to Flash  :", (not switch.value))
print("\tWrite to SD Card:", switch.value)
print("\tboot.py Finis")
###########################################
b-blake commented 2 years ago

The code has evolved. below is the code as it stands now. Also the symptoms have changed on the ItsyBitsy only. If "import microcontroller" ((Line 13)) is not commented out the device crashes after 4 codes are transmitted ((Line 245)). No error codes given on REPL. A hard reset is required. There was an issue between .mpy and .py library files but that went away for no good reason.
((Problem with .py library files. Replaced with .mpy files. Things OK. Test again with .py, problem gone.))

##
##   IR Relay and translate by B.B.Blake 10/10/2021
##
#################### Import entrincic libraries ####################
import array
import board
import digitalio
from   digitalio import DigitalInOut, Direction, Pull
import neopixel
import pulseio
import pwmio
import time
##import microcontroller # I don't know why we need it, but we do.
#################### Import extrincic libraries ####################
import adafruit_esp32spi
from   adafruit_esp32spi import PWMOut
import adafruit_irremote

#################### Figure out what board we have ####################
Pico, Itsy, QTPy, Fthr, ANRC = False, False, False, False, False
bd    = board.board_id # Ask the AdaFruit OS what board we are using
print("\f" + bd, end=" - ")
if  (bd == "raspberry_pi_pico"):         Pico = True
elif(bd == "adafruit_itsybitsy_rp2040"): Itsy = True
elif(bd == "adafruit_qtpy_rp2040"):      QTPy = True
elif(bd == "adafruit_feather_rp2040"):   Fthr = True
elif(bd == "arduino_nano_rp2040_connect_rp2040"): ANRC = True
else:
    while(True):
        print("Board Not Supported.")
        time.sleep(15)
        pass
print("Board Supported.")

#################### Set some variables and constants ####################
freq  = 38000 # IR Tone Frequency
duty  = 32768 # IR Tone Duty Cycle, aka 50%

RED     = (255, 0, 0)
GREEN   = (0, 255, 0)
BLUE    = (0, 0, 255)
CYAN    = (0,255,255)
MAGENTA = (255,0,255)
YELLOW  = (255,255,0)
WHITE   = (255, 255, 255)
BLACK   = (0, 0, 0)

AdaFruit = False
## IR Codes from TiVo IR transmitter, the Peanut
SKIP30  = [0xD0, 0x27, 0x30, 0x85] # SKIP30 - TiVo
INPUT   = [0xF4, 0x0B, 0xFB, 0x04] # INPUT - RCA Source Select
## IR Codes from eBay IR transmitter
Skip_1  = [0xBA, 0x45, 0xFF, 0x00]
Skip_2  = [0xB9, 0x46, 0xFF, 0x00]
Skip_3  = [0xB8, 0x47, 0xFF, 0x00]
Skip_4  = [0xBB, 0x44, 0xFF, 0x00]
Skip_5  = [0xBF, 0x40, 0xFF, 0x00]
Skip_6  = [0xBC, 0x43, 0xFF, 0x00]
Skip_7  = [0xF8, 0x07, 0xFF, 0x00]
Skip_8  = [0xEA, 0x15, 0xFF, 0x00]
Skip_9  = [0xF6, 0x09, 0xFF, 0x00]
Skip_10 = [0xE6, 0x19, 0xFF, 0x00]
OK      = [0xE3, 0x1C, 0xFF, 0x00]
## IR Codes from AdaFruit IR transmitter
if(AdaFruit):
    Skip_1  = [0xEF, 0x10, 0xBF, 0x00]
    Skip_2  = [0xEE, 0x11, 0xBF, 0x00]
    Skip_3  = [0xED, 0x12, 0xBF, 0x00]
    Skip_4  = [0xEB, 0x14, 0xBF, 0x00]
    Skip_5  = [0xEA, 0x15, 0xBF, 0x00]
    Skip_6  = [0xE9, 0x16, 0xBF, 0x00]
    Skip_7  = [0xE7, 0x18, 0xBF, 0x00]
    Skip_8  = [0xE6, 0x19, 0xBF, 0x00]
    Skip_9  = [0xE5, 0x1A, 0xBF, 0x00]
    Skip_10 = [0xF3, 0x0C, 0xBF, 0x00]
    OK      = [0xF6, 0x09, 0xBF, 0x00] # aka ENTER/SAVE

#################### Configure things based on the board found ####################
if(Pico == True):
    IR_TX            = board.GP26

    IR_RX            = board.GP2
    IR_PWR           = board.GP1 # Draw power for the CHQ1838 form GPIO pin 1
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True

    R_LED            = DigitalInOut(board.GP6)
    R_LED.direction  = Direction.OUTPUT
    B_LED            = DigitalInOut(board.GP7)
    B_LED.direction  = Direction.OUTPUT
    G_LED            = DigitalInOut(board.GP8)
    G_LED.direction  = Direction.OUTPUT
    R_LED.value, B_LED.value, G_LED.value = True,  True,  True
    time.sleep(0.5)
    R_LED.value, B_LED.value, G_LED.value = False, True, False 

if(Itsy == True):
    IR_TX            = board.TX

    IR_RX            = board.RX  # Pin connected to  IR receiver.
    IR_PWR           = board.D5
    IR_PWR           = DigitalInOut(IR_PWR)
    IR_PWR.direction = Direction.OUTPUT
    IR_PWR.value     = True

    PIXEL_PIN0       = board.NEOPIXEL # NeoPixel #0
    PIXELS_NUM0      = 1              # NeoPixel #0
    PIXEL_BRIGHT0    = 0.25           # NeoPixel #0
    PIXEL_ORDER0     = neopixel.GRB   # NeoPixel #0
    status_light0    = neopixel.NeoPixel(PIXEL_PIN0, PIXELS_NUM0, brightness=PIXEL_BRIGHT0, auto_write=True,  pixel_order=PIXEL_ORDER0)
    status_light0[0] = WHITE
    PIXEL_PIN1       = board.D7       # NeoPixel #1
    PIXELS_NUM1      = 1              # NeoPixel #1
    PIXEL_BRIGHT1    = 0.25           # NeoPixel #1
    PIXEL_ORDER1     = neopixel.RGB   # NeoPixel #1  (In, +5, Gnd, Out]-flat side to Right [RGB]
    status_light1    = neopixel.NeoPixel(PIXEL_PIN1, PIXELS_NUM1, brightness=PIXEL_BRIGHT1, auto_write=True,  pixel_order=PIXEL_ORDER1)
    status_light1[0] = WHITE
    time.sleep(0.5)
    status_light0[0] = BLUE
    status_light1[0] = BLUE

if(QTPy):
    IR_TX            = board.TX

    IR_RX            = board.RX

    PIXEL_PIN0       = board.NEOPIXEL # NeoPixel #0
    PIXELS_NUM0      = 1              # NeoPixel #0
    PIXEL_BRIGHT0    = 0.25           # NeoPixel #0
    PIXEL_ORDER0     = neopixel.GRB   # NeoPixel #0
    status_light0    = neopixel.NeoPixel(PIXEL_PIN0, PIXELS_NUM0, brightness=PIXEL_BRIGHT0, auto_write=True,  pixel_order=PIXEL_ORDER0)
    status_light0[0] = WHITE 
    time.sleep(0.5)
    status_light0[0] = BLUE

if(Fthr):
    IR_TX            = board.TX

    IR_RX            = board.RX

    PIXEL_PIN0       = board.NEOPIXEL # NeoPixel #0
    PIXELS_NUM0      = 1              # NeoPixel #0
    PIXEL_BRIGHT0    = 0.25           # NeoPixel #0
    PIXEL_ORDER0     = neopixel.GRB   # NeoPixel #0
    status_light0    = neopixel.NeoPixel(PIXEL_PIN0, PIXELS_NUM0, brightness=PIXEL_BRIGHT0, auto_write=True,  pixel_order=PIXEL_ORDER0)
    status_light0[0] = WHITE 
    time.sleep(0.5)
    status_light0[0] = BLUE

if not QTPy: LED           = DigitalInOut(board.LED)
if not QTPy: LED.direction = Direction.OUTPUT

#################### Create IR encoder and decoder ####################
# Create pulse INPUT and IR decoder.
pulses  = pulseio.PulseIn(IR_RX, maxlen=200, idle_state=True)
#pulseout = pulseio.PulseOut(IR_TX, frequency=freq, duty_cycle=duty) Duplicate
decoder = adafruit_irremote.GenericDecode()

## Create a 'pwmio' OUTPUT, to send infrared signals on the IR transmitter @ 38KHz
pwm = pwmio.PWMOut(IR_TX, frequency=freq, duty_cycle=duty) 
pulseout = pulseio.PulseOut(pwm)
## Create an encoder that will take numbers and turn them into NEC IR pulses
encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], zero=[562,  562], one=[562, 1687], trail=562, debug=False) 
##encoder = adafruit_irremote.GenericTransmit((9500, 4500), (562, 1687), (562, 562), 562)
print("#"*80)

#################### Function Definitions ####################
## Fuzzy pulse comparison function:
def fuzzy_pulse_compare(pulse1, pulse2, fuzzyness=0.2):
    if(Pico): R_LED.value, G_LED.value, B_LED.value = False, False, False
    if(Itsy): status_light0.fill(BLACK)
    if(Itsy): status_light1.fill(BLACK)
    if(QTPy): status_light0.fill(BLACK)
##    print(len(pulse1), len(pulse2))
    if len(pulse1) != len(pulse2):
##        print("Pulse Lengths don't match.")
        if(Pico): B_LED.value = True
        if(Itsy): status_light0.fill(BLUE)
        if(Itsy): status_light1.fill(BLUE)
        if(QTPy): status_light0.fill(BLUE)
        return False
    for i in range(len(pulse1)):
        threshold = (int(pulse1[i]) * fuzzyness)
        if abs(pulse1[i] - pulse2[i]) > threshold:
##            print(abs(pulse1[i] - pulse2[i]), i)
            if(Pico): R_LED.value = True
            if(Itsy): status_light0.fill(RED)
            if(Itsy): status_light1.fill(RED)
            if(QTPy): status_light0.fill(RED)
            return False
    if(Pico): G_LED.value = True
    if(Itsy): status_light0.fill(GREEN)
    if(Itsy): status_light1.fill(GREEN)
    if(QTPy): status_light0.fill(GREEN)
    return True

def make_fingerprint(datain, nbits=32, debug=False):
    datax = datain.copy()
    header=[9500, 4500]
    zero=[562,  562]
    one=[562, 1687]
    trail=562
    bits_to_send = len(datax) * 8
    if nbits is not None and nbits < bits_to_send:
        bits_to_send = nbits
    durations = array.array("H", [0] * (2 + bits_to_send * 2 + (0 if trail is None else 1)))
    durations[0] = header[0]
    durations[1] = header[1]
    if trail is not None:
        durations[-1] = trail
    out = 2
    bit_count = 0
    for byte_index, _ in enumerate(datax):
        byte_count = byte_index  # bbb
    for j in range(byte_count, -1, -1): # bbb
        for i in range(7, -1, -1): # bbb
            bit = datax[j] & 1 # bbb
            datax[j] = datax[j] >> 1 # bbb
            if(bit): # bbb
                durations[out] = one[0]
                durations[out + 1] = one[1]
            else:
                durations[out] = zero[0]
                durations[out + 1] = zero[1]
            out += 2
            bit_count += 1
            if bit_count >= bits_to_send:
                break
    if debug:
        print(durations)
    return(durations)

def skip_loop(loops):
    time.sleep(1)
    if not QTPy: LED.value = True
    for xx in range(loops):
        print(loops-xx, end=" ")
##        print( SKIP30 ) # [0xD0, 0x27, 0x30, 0x85] # SKIP30
##        IR_Command = [0xD0, 0x27, 0x30, 0x85] # SKIP30
        Ky = [0xD0, 0x27, 0x30, 0x85]
        IR_Command = Ky.copy()
##        print(SKIP30, IR_Command, Ky, 1)
        encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
##        print(SKIP30, IR_Command, Ky, 2)
        time.sleep(0.5)
    print("")
    if not QTPy: LED.value = False

def reverse_bits(IN):
    OUT = [0,0,0,0]
    Ks = IN.copy()
    for y in range(8): # Reverse the bits.
        for x in range(4): # Bytes 1 thru 4
            Bit     = (Ks[x] & 1)
            Ks[x]   = (Ks[x] >> 1)
            OUT[3-x] = ((OUT[3-x] << 1) + Bit)
    return(OUT)

#################### Main program ####################
ion = False
while ion: # Just print what the IR receiver receives
    time.sleep(0.3)
    pulses.clear()
    time.sleep(0.4)
    pulses.resume()
    time.sleep(0.3)
    pulse1 = decoder.read_pulses(pulses)
    print("IR Code Received")
    print(len(pulse1))
    print(pulse1)
    print("#"*80)
while not ion: # Perform actions depending what the IR receiver receives
##   Loop waiting to receive pulses.
    while True:
        if(AdaFruit): IR_ = 'AdaFruit'
        else:         IR_ = 'eBay'
        time.sleep(0.1)
        pulses.clear()
        time.sleep(0.1)
        pulses.resume()
        time.sleep(0.1)
        print('IR listener started...')
        # Wait for an IR Code to be detected.
        detected = decoder.read_pulses(pulses)
##        print(detected)
        print('got an IR Code...')
        # Got an IR Code, now compare.
        if fuzzy_pulse_compare(make_fingerprint(INPUT), detected, 0.5):
            print('Received correct INPUT TiVo/RCA remote control press!')
            print('Send Command to turn off the Source Select menu on the TV screen.')
            time.sleep(0.5)
            IR_Command = [0xF4, 0x0B, 0xFB, 0x04] # INPUT - Clear TV Screen
            encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
            skip_loop(7)
        elif fuzzy_pulse_compare(make_fingerprint(OK), detected, 0.5):
            print('Received correct OK '+IR_+' remote control press!')
            pass
        elif fuzzy_pulse_compare(make_fingerprint(SKIP30), detected, 0.5):
            print('Received correct SKIP30 TiVo remote control press!')
            pass
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_1), detected, 0.5)):
            print('Received Skip_1 '+IR_+' remote control press!')
            skip_loop(1)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_2), detected, 0.5)):
            print('Received Skip_2 '+IR_+' remote control press!')
            skip_loop(2)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_3), detected, 0.5)):
            print('Received Skip_3 '+IR_+' remote control press!')
            skip_loop(3)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_4), detected, 0.5)):
            print('Received Skip_4 '+IR_+' remote control press!')
            skip_loop(4)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_5), detected, 0.5)):
            print('Received Skip_5 '+IR_+' remote control press!')
            skip_loop(5)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_6), detected, 0.5)):
            print('Received Skip_6 '+IR_+' remote control press!')
            skip_loop(6)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_7), detected, 0.5)):
            print('Received Skip_7 '+IR_+' remote control press!')
            skip_loop(7)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_8), detected, 0.5)):
            print('Received Skip_8 '+IR_+' remote control press!')
            skip_loop(8)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_9), detected, 0.5)):
            print('Received Skip_9 '+IR_+' remote control press!')
            skip_loop(9)
        elif(fuzzy_pulse_compare(make_fingerprint(Skip_10), detected, 0.5)):
            print('Received Skip_10 '+IR_+' remote control press!')
            skip_loop(10)
        else:
            print(detected)
            pass
        if(Pico): G_LED.value = False
        if(Itsy): status_light0.fill(BLACK)
        if(Itsy): status_light1.fill(BLACK)
        if(QTPy): status_light0.fill(BLACK)
        time.sleep(0.1)
        pulses.clear()
        time.sleep(0.1)
        pulses.resume()
        time.sleep(0.1)
        print("#"*80)
dhalbert commented 2 years ago

When you say "crash", do you mean that it just hangs, as opposed to reseting into safe mode or throwing an exception?

b-blake commented 2 years ago

Crash = No exception thrown, no safe mode, it stops responding to all REPL commands Ctrl-C, Ctrl-D, etc. After ~45 seconds it disconnects from my Windows 10 machine then I get an alert box with "USB device not recognized" when it tries to connect. Pushing RESET brings it back.

Bruce

b-blake commented 2 years ago

With further experimentation...

It is not import microcontroller that alone is the issue. I added code, modified code, and removed code with no issue, no crashes.

Then I made a minor change and the crashes came back at a different place. It was after 4 SKIP30 sends, now it is after 10 SKIP30 sends. It can be 10 sends at one time or two of 5 sends. I stopped the crashes this time by adding import supervisor. supervisor is never called, but the crashes stopped.

I am starting to suspect complied object code size. Is there a way to find out if, where, and when the object code, variables, or lists fall on a memory boundary(s)?

Bruce

dhalbert commented 2 years ago

I don't think it is just size. There is memory corruption somewhere. You might leave all these imports in and turn off various parts of the program with if False: etc.

b-blake commented 2 years ago

Dan,

I have narrowed it down to this function call: print(SKIP30, IR_Command, Ky, 1) encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32) print(SKIP30, IR_Command, Ky, 2)

Encoder is defined much earlier by:

## Create an encoder that will take numbers and turn them into NEC IR pulses
encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], zero=[562,  562], one=[562, 1687], trail=562, debug=False)

I have no control over adafruit_irremote or the intrinsic functions it calls. I doubt they are part of the issue.

The code crashes after the first print call but before the second. Previously when it was crashing at 4 SKIP30 calls there was a bunch of diagnostic code and lots of crap coding. When I cleaned up a bunch of the crap code and diagnostic stuff, the issue went away. When I added in some code to make the program more flexible the crashes cam back. So size is a tell; as to what/where, I have no clue.

Your idea about memory corruption is interesting because the issue only happens in my ItsyBitsy RP2040. It does not raise its ugly head on my QT Py RP2040, Feather RP2040, or Raspberry Pi Pico. I started development on the RPi Pico but wanted to make it portable to the other RP2040 platforms. (Don't tell anybody, but the AdaFruit platforms are better in several ways.) There was also an issue of bad algorithm execution on the ItsyBitsy that went away for no discernable reason. Not working with .py library. Working with .mpy library. *Working with .py library. Trying to isolate to an .py library issue didn't work. Both started working. So much for that idea.

Bruce

dhalbert commented 2 years ago

There have been changes in the native PulseOut code recently. I suspect that some memory or timing problem may be coming from that. @DavePutz and @tannewt may be interested in this bug.

DavePutz commented 2 years ago

I have not been able to reproduce this on my RP2040 ItsyBitsy running CP 7.0.0. Can I ask you to add an import of the gc module and then put a 'print ("Mem Free: ", gc.mem_free())' right before the encoder.transmit line? This will show us if we're running low on memory as a possible cause. Thanks!

b-blake commented 2 years ago

Dave,

Here ya go. Crash after 4 IR commands sent. No joy in Mudville.

IR listener started... got an IR Code... Received Skip_10 eBay remote control press! 10 Mem Free: 174944 9 Mem Free: 174256 8 Mem Free: 173568 7 Mem Free: 172880

b-blake commented 2 years ago

Dave,

GC Supervisor

OFF      OFF = Crash @ 4  sends
ON       ON  = OK

Insert print mem statement

OFF      ON   = Crash @ 7
On       OFF  = Crash @ 4

Print mem commented out OFF OFF = OK Delete print statement OFF OFF = OK Delete import gc, Import supervisor commented out OFF OFF = OK Remove # from import supervisor compile error - - - - 7 good loops then throw error code. No crash this time. Received Skip_10 eBay remote control press!

10 9 8 7 6 5 4 Traceback (most recent call last):
  File "code.py", line 381, in <module>
  File "code.py", line 287, in skip_loop
  File "adafruit_irremote.py", line 377, in transmit
TypeError: can't convert NoneType to int

This is line 381 skip_loop(10) This is skip_loop(foo)

def skip_loop(loops):
    time.sleep(1)
    for xx in range(loops):
        if not QTPy: LED.value = True
        print(loops-xx, end=" ")
        IR_Command = SKIP30.copy()
###        print(SKIP30, IR_Command, 1)
        encoder.transmit(pulseout, reverse_bits(IR_Command), nbits=32)
###        print(SKIP30, IR_Command, 2)
        if not QTPy: LED.value = False
        time.sleep(0.5)
    print("")
dhalbert commented 2 years ago

[ @b-blake you can put code or output in triple back-ticks (or single if it's one line). I have been editing your posts a bit to do that. You can use the "< >" button in the post editor. Select what needs to be shown as code or output and then click the button. ]

b-blake commented 2 years ago

Dave, Dan,

Thank you.

Bruce

DavePutz commented 2 years ago

Well, that's clear evidence that memory is getting stepped on. Line 377 in adafruit_irremote.mpy is durations[out] = self.one[0] in the transmit function. The 'out' variable is a simple integer, so something has corrupted where it is stored. I will continue to attempt to reproduce the issue. May I ask what hardware you are using for the IR receiver and transmitter (in case that may be having some impact here).

b-blake commented 2 years ago

Dave,

The Line 377 error drop is the first real clue I saw. Previously all I got was a crash. If you can't reproduce my symptoms, I have .zip file with ALL that is on the ItsyBitsy. It is 980MB so quite big. If I remove the lib subdirectory it drops in size considerably. The library DTG is 10/2/2021 @ 12:59 PM. I agree the IR parts should not have an effect, but . . .

IR (Infrared) Receiver Sensor - TSOP38238 PRODUCT ID: 157 Pin #1 goes to the RX pin on the ItsyBitsy. Ground to the center pin #2. +5 Vcc/USB to pin #3 of the IR receiver

Super-bright 5mm IR LED - 940nm PRODUCT ID: 387 The TX LEDs are driven by a 2N3904 NPN transistor with 5.1k Ohm resistor from Base to the TX pin on the ItsyBitsy. Emitter to Ground. Collector to a 57 Ohm resistor to a pair of IR LEDs in series to +5 Vcc/USB.

If you toggle the AdaFruit variable to True, this remote's IR codes will be understood by the program. Mini Remote Control PRODUCT ID: 389

Bruce

DavePutz commented 2 years ago

Bruce,

Just curious; is there a reason you are using the esp32spi PWMOut instead of the RP2040 PWMOut that is part of pwmio? I've tried both and saw no hangs with either; but I was wondering why you did things that way.

Dave

dhalbert commented 2 years ago

@DavePutz I think @b-blake is using the native pwmio.PWMOut. These are the imports:

import pwmio
from   adafruit_esp32spi import PWMOut

and this is the sole use I see:

pwm = pwmio.PWMOut(IR_TX, frequency=freq, duty_cycle=duty)
b-blake commented 2 years ago

@DavePutz Dave,

is there a reason you are using the esp32spi PWMOut instead of the RP2040 PWMOut that is part of pwmio?

Yes, a very sophisticated reason. It is what I copied off of the AdaFruit web site and github. If had stumbled on code that uses RP2040 PWMOut, that is what I would have used. How would I use it? P.S. I had to look up how to spell 'sophisticated' ;-)

@dhalbert Dan,

See above. No sophisticated reasons for what I do. My only class on programming was for FORTRAN back in 1966 and I just sat in on it while my girlfriend took the class. After that one class, I started playing with the IBM 1620 that was in the U of Wisconsin Space Astronomy Laboratory where I worked for $1.00/hour. FORGO, BASIC, QBASIC, Assembly on 3 platforms, Pearl, Python, and Circuit Python have all been self taught.

Bruce

b-blake commented 2 years ago

@DavePutz Dave,

OK... I made the following change.

from   pwmio import PWMOut
#from   adafruit_esp32spi import PWMOut

What have I made better by doing this? Eliminating the need for adafruit_esp32spi is a plus, but is there more?

Bruce

b-blake commented 2 years ago

With the above change I get the following on the second push of Skip 10;

Traceback (most recent call last):
  File "code.py", line 345, in <module>
NameError: name 'OK' is not defined

The error goes away when I import supervisor.

Bruce

b-blake commented 2 years ago

A reminder. It only happens on the ItsyBitsy. What is so unique with the ItsyBitsy? The errors/crashes do not happen on the Raspberry Pi Pico or the QT Py. To my mind the QT Py is no more than a folded ItsyBitsy.

dhalbert commented 2 years ago

The from adafruit_esp32spi import PWMOut should be irrelevant, because the only use of PWMOut is in pwmio.PWMOut. If removing the from adafruit_esp32spi import PWMOut affects the bug, then that points even more to some kind of memory problem, where random changes about what's in RAM cause problems at different places in the program.

ItsyBitsy vs Pi Pico vs QT Py also points to that. The ItsyBitsy has more definitions in board, and some other slight differences. It is just an accident that we are seeing the problem on the Itsy and not the other boards. I would guess the boards may have memory corruption as well: the corruption is just affecting something else, which is less obvious.

b-blake commented 2 years ago

@dhalbert Dan,

Removing the from adafruit_esp32spi import PWMOut does not affect the bug. Of all the people in all the world using CP 7.0.0, why only me? Is it that obscure?

Bruce

P.S. Dan, I am watching laundry wash, what is your excuse for not enjoying Saturday? Get a 6-pack of PBR or a bottle of T-Bird and sit by the lake and relive your teens. Take your SO with you and make bad decisions.

b-blake commented 2 years ago

Dan,

where random changes about what's in RAM cause problems at different places in the program.

At one point I was getting wrong IR output with the .py library, but when I changed to the .mpy library the problem went a way.

Bruce

b-blake commented 2 years ago

Guys,

With the latest change;

from pwmio import PWMOut

I now can get the Feather to crash.

DavePutz commented 2 years ago

Well, I've managed to re-create memory corruption using a Pico. Now the issue is hunting down the source of the problem.

b-blake commented 2 years ago

Dave,

I wish you the best of luck. I am available for testing at any time. Being retired has its advantages.

Bruce

DavePutz commented 2 years ago

It looks like the issue can occur when an incoming pulse (even a stray IR signal) comes in while sending the pulseout. The following stack was captured:

#0  0x10040b4a in common_hal_pulseio_pulsein_interrupt (self=0x20009200) at common-hal/pulseio/PulseIn.c:148
#1  0x1003468a in rp2pio_statemachine_interrupt_handler () at common-hal/rp2pio/StateMachine.c:819
#2  <signal handler called>
#3  0x200025aa in supervisor_run_background_tasks_if_tick () at ../../supervisor/shared/tick.c:127
#4  0x10041164 in common_hal_pulseio_pulseout_send (self=self@entry=0x20009330, pulses=<optimized out>,
    length=<optimized out>) at common-hal/pulseio/PulseOut.c:132
#5  0x1004ac6c in pulseio_pulseout_obj_send (self_in=0x20009330, pulses=0x2000f4f0)
    at ../../shared-bindings/pulseio/PulseOut.c:151

Investigating how to handle this.

DavePutz commented 2 years ago

Bruce,

     Are you able to pull and build this test patch? https://github.com/DavePutz/circuitpython.git,  branch issue_5469.

If not we'll have to work out some other way to get you some test uf2s.

Dave

dhalbert commented 2 years ago

If not we'll have to work out some other way to get you some test uf2s.

You can zip the .uf2 and attach it to an issue comment.

DavePutz commented 2 years ago

Bruce,,

    Attached is a zip file with uf2s for Pico, ItsyBitsy, and Feather. If you can test, let me know how it goes; thanks!

issue_5469_test.zip

b-blake commented 2 years ago

Dave, Dan,

I have not been able to cause a crash or memory violation on the three platforms that replacement *uf2 files were provided for. As I do not trust electronics, I will never say it is 100% fixed. I have been bit too many times ;-)

When will this change be posted to BROWSE S3?

Thank you both very much for all your help.

Bruce

b-blake commented 2 years ago

Dave,

I am trying adafruit-circuitpython-arduino_nano_rp2040_connect-en_US-20211025-66e7dbe.uf2 on my Nano RP2040 Connect and the issue shows its ugly head. No add or subtract of libraries makes it work.

Am I using old code?

Bruce

DavePutz commented 2 years ago

Bruce,

    As far as I know the Pull Request has not been merged, so there is

no build yet on circuitpython.org that includes it. You can follow the Pull Request (at https://github.com/adafruit/circuitpython/pull/5509 ) and after it is approved and merged it will be in the latest build(s). Hope this helps,

     Dave

On Mon, Oct 25, 2021 at 2:45 PM b-blake @.***> wrote:

Dave,

I am trying adafruit-circuitpython-arduino_nano_rp2040_connect-en_US-20211025-66e7dbe.uf2 on my Nano RP2040 Connect and the issue shows its ugly head. No add or subtract of libraries makes it work.

Am I using old code?

Bruce

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adafruit/circuitpython/issues/5469#issuecomment-951251014, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFNJKEVVOFTJVQR526W34HTUIWXUTANCNFSM5GCPYWTQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

dhalbert commented 2 years ago

Fixed by #5509.

b-blake commented 2 years ago

My Nano RP2040 Connect is happy now.

Thanks Dave and Dan.

Bruce