Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rp2: Dual core code behaves non-deterministically driving UART #7977

Closed
peterhinch opened this issue Nov 5, 2021 · 2 comments
Closed

rp2: Dual core code behaves non-deterministically driving UART #7977

peterhinch opened this issue Nov 5, 2021 · 2 comments
Labels

Comments

@peterhinch
Copy link
Contributor

peterhinch commented Nov 5, 2021

The following runs for a while before the other thread on the second core stops UART output. The other thread continues to run, as evidenced by the incrementing g value. In my actual application I have seen UART output restart and stop again periodically, sometimes over times of many seconds.

Similar code with multiple uasyncio tasks outputting to the UART but running on one core works as expected.

If you change things in the code such as the type of g, the presence or absence of the sleep_ms(20) or whether foo is started, the UART behaviour changes but not in a way which seems to make sense. In every case the code runs: it is only the UART output which is unexpected.

import _thread
from time import sleep_ms
import uasyncio as asyncio
from machine import UART

u = UART(0, 1_000_000)

lock = _thread.allocate_lock()
g = 1.0  # 'a'

def other():
    global g
    while True:
        u.write('A')
        lock.acquire()
        # Proof of code running.
        g += 0.1  #  g += 'a'
        sleep_ms(20)  # Commenting-out can alter behaviour
        lock.release()
        u.write('a')
        sleep_ms(100)

async def foo():
    while True:
        u.write(b'\x40')  # @
        await asyncio.sleep_ms(0)
        u.write(b'\x60')  # `
        await asyncio.sleep_ms(0)

async def main():
    u.write('z')
    asyncio.create_task(foo())  # Commenting-out can alter behaviour
    _thread.start_new_thread(other, ())
    while True:
        u.write('B')
        while lock.locked():
            await asyncio.sleep_ms(0)
        lock.acquire()
        print(g)
        lock.release()
        u.write('b')
        await asyncio.sleep_ms(103)

asyncio.run(main())
@peterhinch
Copy link
Contributor Author

peterhinch commented Nov 7, 2021

I ran two tests to try to narrow this down.

  1. Changed the interface to SPI: result was the same with erratic behaviour.
  2. Ran on a Pyboard using _thread (and UART): this worked perfectly.

So the issue seems specific to dual core running on RP2.

On the suggestion of Mike Teachman I tried using the lock to protect every UART write (on the theory that re-entrancy might be occurring). This did not fix the problem.

@peterhinch
Copy link
Contributor Author

Fixed by #8310!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants