RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
Post Reply
Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Post by Filip_KONAX » Thu Jun 16, 2022 6:46 am

I could use some help understanding multithreading in micropython (using the second core of the RP2040).
In my mainthread, running on Core 0 of the Pico, I connect to a NB-IoT modem using the hardware UART and AT commands. (I'm having some difficulties there too with processing data while receiving it, see another post.) I decided to have the second core dedicated to treating the I/O logic. For getting started using the second core, I chose the easiest task one can imagine: blink an LED, quite easy I guessed.
But: while Core 0 is doing quite some UART operations (for modem set-up and communication) and some file operations for logging purposes, I see the LED stops blinking. That shouldn't be the case with multithreading on two cores, I would guess or am I missing something fundamental?

I've put my second thread in a separate module and added a lock to exit the infinite loop.

Code: Select all

import time
import _thread
from machine import Pin
from iopins import *

def main(log, mainThreadRunningSemaphore):
    print("Starting up second Thread...")
    while mainThreadRunningSemaphore.locked():
        time.sleep(1)
        OUT_1.toggle()
        # We release the traffic light lock
        #lock.release()
    print("Exiting second Thread")
    _thread.exit()
This is how I start my second thread in my main.py:

Code: Select all

...
    mainThreadRunningSemaphore = _thread.allocate_lock()
    mainThreadRunningSemaphore.acquire()
    #startup logging
    ...
    #create communication class instance
    ...
    
     _thread.start_new_thread(secondThread.main, [log, mainThreadRunningSemaphore])
     
     #do the modem things here (infinitely)
     ...
     
     #after modem main thread stops
     mainThreadRunningSemaphore.release()
     ...
     
So, the second thread isn't running independently of the first one, is that because of the fact that the interpreter is busy?
Would there be a way to start a second micropython interpreter on the second core in order to have more independance?
Or should I switch to C instead of micropython to have better independance?
Or is this problem maybe hardware interrupt related?
Last edited by Filip_KONAX on Thu Jun 16, 2022 11:53 am, edited 1 time in total.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: RP2 multithreading - Pin - UART - should I switch to C?

Post by pythoncoder » Thu Jun 16, 2022 9:17 am

This is a peculiar use of a lock, whose purpose is normally to control access to a shared resource. While I can't see why your code isn't working, I suggest you replace the lock with a simple shared global boolean, say stop_thread. The two threads can share variables, although care needs to be taken with complex objects like lists.

The two threads on RP2 most definitely do run concurrently. There is no shared GIL.
Peter Hinch
Index to my micropython libraries.

Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

Re: RP2 multithreading - Pin - UART - should I switch to C?

Post by Filip_KONAX » Thu Jun 16, 2022 11:53 am

Hi Peter
Thank you for your reply. I've got the second thread running, not sure what I did though.
My guess is that I didn't realise the modem main thread stopped.
Because I no noticed, that not all print statements produce an output on the REPL.
I've got a logfile that continues after the print statements stopped outputting.
Any clue where to look for a reason why print has stopped?
Also breaking with Ctrl-C doesn't work anymore then.
Did I starve the REPL in some way?

Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Post by Filip_KONAX » Thu Jun 16, 2022 2:46 pm

I think I might have found the solution for the stopping of the printing of the REPL in combination with constant uart usage.
I introduced on different locations in my code sleep_ms calls, what seels to give time to the REPL to process the printing.
Is this the way-to-go or are there better ways to cope with this problem?
If this is the way-to-go, how long should I put my script to sleep?

Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Post by Filip_KONAX » Thu Jun 16, 2022 3:08 pm

Just upgraded to v1.19. Seems to work better.
I'll keep you posted!

Still wondering (see above) if putting sleep statements is the way-to-go...?

Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

Re: RP2 multithreading - Pin - UART - should I switch to C?

Post by Filip_KONAX » Thu Jun 16, 2022 3:35 pm

pythoncoder wrote:
Thu Jun 16, 2022 9:17 am
This is a peculiar use of a lock, whose purpose is normally to control access to a shared resource. While I can't see why your code isn't working, I suggest you replace the lock with a simple shared global boolean, say stop_thread. The two threads can share variables, although care needs to be taken with complex objects like lists.

The two threads on RP2 most definitely do run concurrently. There is no shared GIL.
Hi, I don't succeed using a shared variable for stopping the second thread...
Tried using a global variable, but it doesn't seem I know how to, as the value doesn't seem to change...
Missing something, I guess. Snippet much appreciated!

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Post by pythoncoder » Fri Jun 17, 2022 7:50 am

Try this:

Code: Select all

import _thread
from time import sleep_ms

running = True
count = 0

def other():
    global count
    while running:
        count += 1
        sleep_ms(100)

def main():
    global running
    print("Running...")
    _thread.start_new_thread(other, ())  # Tuple of args
    while count < 100:
        print(count)
        sleep_ms(1000)
    running = False
    print(f"count when thread stopped = {count}")
    sleep_ms(2000)  # Prove that thread has stopped
    print(f"count after thread stopped for 2 secs = {count}")
As a general point, when learning a new technique I always write simple test cases like the above before tackling real applications.
Peter Hinch
Index to my micropython libraries.

Filip_KONAX
Posts: 16
Joined: Wed Jun 08, 2022 1:05 pm

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Post by Filip_KONAX » Fri Jun 17, 2022 10:43 am

Hi Peter
Thank you, feeling a bit stupid. I did put the second thread in a separate module, that's why it wasn't working with a global variable. I didn't need global variable, I just needed to reference the modules namespace! :oops:
pythoncoder wrote:
Fri Jun 17, 2022 7:50 am
Try this:

Code: Select all

import _thread
from time import sleep_ms

running = True
count = 0

def other():
    global count
    while running:
        count += 1
        sleep_ms(100)

def main():
    global running
    print("Running...")
    _thread.start_new_thread(other, ())  # Tuple of args
    while count < 100:
        print(count)
        sleep_ms(1000)
    running = False
    print(f"count when thread stopped = {count}")
    sleep_ms(2000)  # Prove that thread has stopped
    print(f"count after thread stopped for 2 secs = {count}")
As a general point, when learning a new technique I always write simple test cases like the above before tackling real applications.

Post Reply