I made a solar powered temperature sensor using Micropython on a Pico W and have been using a NANO Timer on my Pico W solar powered sensor to conserve battery power.
However, if the program hangs then the DONE signal is not sent to the NANO Timer and the battery power is consumed until a board reset enables the proper running of the program.
I tried using the onboard WatchDog Timer, but it has a maximum timeout of 8331 ms. Which made debugging difficult.
Eventually I found that there was some sort of problem with the Micropython sleep() function and WiFI.
I decided to try and create a PIO trigger to reset the NANO Timer. Not knowing much about PIO I used Google Gemini as coding buddy (with a Youtube channel 'Life with David' ) and was able to create a basic countdown timer. It worked as a one time trigger, but I couldn’t reset (feed) the countdown. My problem was not clearing the OSR, but with the help of the forum post viewtopic.php?t=347682#p2082827 Iwas able to implement a suitable countdown timer that could be fed like a watchdog timer.
The following is my implementation of a PIO based countdown timer that can be used to trigger an action such as a DONE signal for the NANO Timer or a reset to external circuitry on the RUN pin of the Pico. The following article has been useful for implementing that on a powered Pico, viewtopic.php?t=308166&start=25
The NANO Timer can be found at https://core-electronics.com.au/makerve ... -pico.html
In one application I cut the header pin that connects to the Pico VBUS so I could connect a solar panel to the VBUS pin on the NANO Timer. and use the board's charging circuit for a LiPo.
Not sure if this is of any value, but I had to learn a lot to get this all done and it was from others posting that I was able to solve my problems.
I found the Youtube channel 'Life with David' specifically his playlist 'Raspberry PI Pico PIO' https://www.youtube.com/playlist?list=P ... 2NUmk_mtEI
There is a specific clip on PIO Interrupts
https://youtu.be/AaxrtL4SZHQ?si=tr2xIKqTy9-AQu6g
I used interrupts from the PIO and outputting numbers to be able to debug/track the PIO program.
Thanks to all that contribute to shared knowledge and experience.
However, if the program hangs then the DONE signal is not sent to the NANO Timer and the battery power is consumed until a board reset enables the proper running of the program.
I tried using the onboard WatchDog Timer, but it has a maximum timeout of 8331 ms. Which made debugging difficult.
Eventually I found that there was some sort of problem with the Micropython sleep() function and WiFI.
I decided to try and create a PIO trigger to reset the NANO Timer. Not knowing much about PIO I used Google Gemini as coding buddy (with a Youtube channel 'Life with David' ) and was able to create a basic countdown timer. It worked as a one time trigger, but I couldn’t reset (feed) the countdown. My problem was not clearing the OSR, but with the help of the forum post viewtopic.php?t=347682#p2082827 Iwas able to implement a suitable countdown timer that could be fed like a watchdog timer.
The following is my implementation of a PIO based countdown timer that can be used to trigger an action such as a DONE signal for the NANO Timer or a reset to external circuitry on the RUN pin of the Pico. The following article has been useful for implementing that on a powered Pico, viewtopic.php?t=308166&start=25
Code:
# PIO_delay.py## Uses the PIO to generate a delayed trigger HIGH on pin.# Can use as a reset with external circuit, even when main loop fails (hangs)#import rp2import utimefrom machine import Pin@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW, autopull=True)def PIO_watchdog(): # Will set a pin high after it has countdown to zero. Can be restarted with new loop count. # --- Initialization --- # Pull a 32-bit loop count from the FIFO into the OSR. pull() # Load initial loop count into OSR. Auto pull will load values after PIO starts label("data_available") # used when not_osre -> OSR is NOT empty and has new value # Get latest loop count. Clear the OSR so that it only becomes non-empty when new data is provided. out(x, 32) # Output into X register from OSR (clearing it); FIFO now empty. # --- Main Delay Loop --- label("wait_delay") # Check if new delay data is available in the FIFO: jmp(not_osre, "data_available") # If OSR is filled (new data available), jump to reload branch. # No new data: continue countdown. jmp(x_dec, "wait_delay") # Decrement X and loop until it reaches zero. # When countdown reaches zero, trigger the event. set(pins, 1) # Set the output pin HIGH (triggers the external reset circuit). DEBUG_PIO_DELAY = True#DEBUG_PIO_DELAY = Falsedef calculate_delay_count(delay_seconds, PIO_freq): # Calculate the value to send to the PIO # Delay loop takes 2 cycles (each jmp instruction takes 1 cycle) # Target loop Count = delay_secs (seconds) * PIO_freq (cycles/seconds) / 2 cycles loop_count_for_pio = int(delay_seconds * (PIO_freq /2)) if DEBUG_PIO_DELAY: print(f'Required delay {delay_seconds} seconds, PIO Clock frequency: {PIO_freq}, calculated delay value {loop_count_for_pio}') return loop_count_for_pio # -------------------------------------------------# Helper funtion enable_PIO_watchdog sets up the PIO and calculates delay countdef enable_PIO_watchdog(delay_seconds=100, trigger_pin=Pin(22, Pin.OUT)): #set pin low trigger_pin.low() # Use a PIO frequency that works for the delay calculation PIO_freq = 100_000 # Get the PIO instance and load the program sm = rp2.StateMachine(0, PIO_watchdog, freq=PIO_freq, set_base=trigger_pin) if DEBUG_PIO_DELAY: print(f'Trigger Pin is {trigger_pin}') # calculate the loop count for the required delay loop_count_for_pio = calculate_delay_count(delay_seconds, PIO_freq) # Run the state machine sm.active(1) # Put the loop count into the PIO's TX FIFO # The PIO will pull this value then start, subsequent puts are auto pulled sm.put(loop_count_for_pio) # return state machine instance and calculated delay for later use if needed return sm, loop_count_for_pio# -------------------------------------------------# Helper function feed_watchdog wraps the PIO state machine put function for readiabilitydef feed_watchdog(sm, delay_count): sm.put(delay_count)# --- Example Usage ---if __name__ == "__main__": # Define the pin for the watchdog trigger WATCHDOG_PIN = Pin(22, Pin.OUT) import time start_tick_ms = time.ticks_ms() sm, delay_count = enable_PIO_watchdog(trigger_pin=WATCHDOG_PIN, delay_seconds=20) # Main loop: Feed the watchdog every defined interval while True: utime.sleep_ms(2000) elapsed_time = (time.ticks_ms()-start_tick_ms)/1000 print(" Time ", elapsed_time) if int(elapsed_time) <= 10: # feeds the watch dog, can change delay count to expected max time in each section feed_watchdog(sm, delay_count) # helper function for sm.put(delay_count)The NANO Timer can be found at https://core-electronics.com.au/makerve ... -pico.html
In one application I cut the header pin that connects to the Pico VBUS so I could connect a solar panel to the VBUS pin on the NANO Timer. and use the board's charging circuit for a LiPo.
Not sure if this is of any value, but I had to learn a lot to get this all done and it was from others posting that I was able to solve my problems.
I found the Youtube channel 'Life with David' specifically his playlist 'Raspberry PI Pico PIO' https://www.youtube.com/playlist?list=P ... 2NUmk_mtEI
There is a specific clip on PIO Interrupts
https://youtu.be/AaxrtL4SZHQ?si=tr2xIKqTy9-AQu6g
I used interrupts from the PIO and outputting numbers to be able to debug/track the PIO program.
Thanks to all that contribute to shared knowledge and experience.
Statistics: Posted by PicoP — Sat Jul 12, 2025 5:12 am — Replies 0 — Views 28