`with` statement in loop takes cyclically increasing time
import pyb
class WithTest:
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, *exc):
pass
x1 = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.OUT_PP)
# CYCLICALLY INCREASING INTERVALS
wt = WithTest()
while True:
with wt as wtx:
x1.value(not x1.value())
#OK: CONSTANT INTERVALS
while True:
with WithTest() as wt:
x1.value(not x1.value())
The first loop in this test program produces a cyclically increasing square wave. I tested on a PyBoard v1.1 with v1.94 and the also the latest build pybv11-20200208-v1.12-154-gce40abcf2.dfu
The period of the waveform increases from about 38 microseconds to about 240 microseconds. Then there's a gap (gc?) and it starts over.
If you comment out the first loop and use the second (which constructs the with object over and over), it runs at a constant 180 microseconds or so.
The fact that it's a with statement is important; The as is not necessary. We first discovered this while doing I2C transactions in CircuitPython which were taking too long. It took a while to figure out that it was not an I2C issue, but was solely due to the with.
I don't see why the with should inherently cause this behavior, so I think there's something going on in the VM that's slowing things down on each iteration, probably allocating storage which finally gets gc'd. But why should we see an increasing interval? It's like something is walking down an increasingly longer list.
This is easiest to see on an oscilloscope:
https://youtu.be/tGB2uVwig_4 (unlisted; use the link)
Screen shots from Saleae:
first loop (taken at gap: starts fast after a gap and slows down):

second loop (constant before and after gap):

Also filed as https://github.com/adafruit/circuitpython/issues/2602.
uasyncio stream reader/writer: unexpected behaviour with UART
Testing done on Pyboard V1.1. The sender coroutine iterates every 2 seconds but no output appears on pin X1:
import uasyncio as asyncio
from pyb import UART
uart = UART(4, 9600)
async def sender():
swriter = asyncio.StreamWriter(uart, {})
while True:
swriter.awrite('Hello uart\n')
await asyncio.sleep(2)
print('wrote')
loop = asyncio.get_event_loop()
loop.create_task(sender())
loop.run_forever()
The next script produces output on X1 as expected until a loopback is applied (link X1 and X2). At this point the UART sends data continuously. The data is read correctly, but the call to
await asyncio.sleep(2) no longer behaves as expected.
import uasyncio as asyncio
from pyb import UART
uart = UART(4, 9600)
async def sender():
while True:
uart.write('Hello uart\n')
await asyncio.sleep(2)
print('Wrote')
async def receiver():
sreader = asyncio.StreamReader(uart)
while True:
res = await sreader.readline()
print('Recieved', res)
loop = asyncio.get_event_loop()
loop.create_task(sender())
loop.create_task(receiver())
loop.run_forever()