From d899710e43a1f7966261f41f1bd5baf00b20f623 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sat, 20 Oct 2018 15:31:09 +0100 Subject: [PATCH 1/3] Fails on ESP8266 after ~1000 passes. --- i2c/asi2c.py | 36 ++++++++++++++++++++++++++++-------- i2c/asi2c_i.py | 6 ++++-- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/i2c/asi2c.py b/i2c/asi2c.py index ade4ea4..59e39ad 100644 --- a/i2c/asi2c.py +++ b/i2c/asi2c.py @@ -27,6 +27,10 @@ import utime from micropython import const, schedule import io +import gc + +import micropython +micropython.alloc_emergency_exception_buf(100) _MP_STREAM_POLL_RD = const(1) _MP_STREAM_POLL_WR = const(4) @@ -36,6 +40,8 @@ # between Initiator setting a pin and initiating an I2C transfer: ensure # Initiator sets up first. _DELAY = const(20) # μs +# bytes objects are transmitted in blocks of size 16N where N is an integer +upsize = lambda x : (x + 15) & ~15 # Base class provides user interface and send/receive object buffers class Channel(io.IOBase): @@ -52,8 +58,12 @@ def __init__(self, i2c, own, rem, verbose, rxbufsize): self.txbyt = b'' # Data to send self.txsiz = bytearray(2) # Size of .txbyt encoded as 2 bytes self.rxbyt = b'' - self.rxbuf = bytearray(rxbufsize) + self.rxbuf = bytearray(upsize(rxbufsize)) # Hold an integer no. of blocks self.rx_mv = memoryview(self.rxbuf) + self.lstmv = [] + for n in range(16, len(self.rxbuf) + 16, 16): # Preallocate memoryviews + self.lstmv.append(self.rx_mv[0 : n]) # for all data lengths + self.nrx = 0 # No. of bytes received (ignoring padding) self.cantx = True # Remote can accept data async def _sync(self): @@ -72,7 +82,7 @@ def waitfor(self, val): # Initiator overrides # Get incoming bytes instance from memoryview. def _handle_rxd(self, msg): - self.rxbyt = bytes(msg) + self.rxbyt = bytes(msg[:self.nrx]) def _txdone(self): self.txbyt = b'' @@ -122,7 +132,8 @@ def write(self, buf, off, sz): d = buf[off : off + sz] d = d.encode() l = len(d) - self.txbyt = d + # Pad to integer no. of blocks + self.txbyt = b''.join((d, bytes(upsize(l) - l))) self.txsiz[0] = l & 0xff self.txsiz[1] = l >> 8 return l @@ -148,19 +159,27 @@ class Responder(Channel): rxbufsize = 200 def __init__(self, i2c, pin, pinack, verbose=True): super().__init__(i2c, pinack, pin, verbose, self.rxbufsize) + self._handle_rxd_ref = self._handle_rxd # Alocate RAM here + self._re_enable_ref = self._re_enable loop = asyncio.get_event_loop() loop.create_task(self._run()) async def _run(self): await self._sync() # own pin ->0, wait for remote pin == 0 - self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING) + self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING, hard = True) + while True: + await asyncio.sleep(1) + gc.collect() + + def _re_enable(self, _): + self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING, hard = True) # Request was received: immediately read payload size, then payload # On Pyboard blocks for 380μs to 1.2ms for small amounts of data def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): # tstart = utime.ticks_us() # TEST addr = Responder.addr - self.rem.irq(handler = None, trigger = machine.Pin.IRQ_RISING) + self.rem.irq(handler = None, trigger = machine.Pin.IRQ_RISING, hard = True) utime.sleep_us(_DELAY) # Ensure Initiator has set up to write. self.i2c.readfrom_into(addr, sn) self.own(1) @@ -171,12 +190,13 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): if n: self.waitfor(1) utime.sleep_us(_DELAY) - mv = memoryview(self.rx_mv[0 : n]) # allocates + mv = self.lstmv[(n >> 4)] self.i2c.readfrom_into(addr, mv) self.own(1) self.waitfor(0) self.own(0) - schedule(self._handle_rxd, mv) # Postpone allocation + self.nrx = n + schedule(self._handle_rxd_ref, mv) # Postpone allocation self.own(1) # Request to send self.waitfor(1) @@ -198,5 +218,5 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): self.own(0) self.waitfor(0) self._txdone() # Invalidate source - self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING) + schedule(self._re_enable_ref, 0) # print('Time: ', utime.ticks_diff(utime.ticks_us(), tstart)) diff --git a/i2c/asi2c_i.py b/i2c/asi2c_i.py index 2a08735..4586515 100644 --- a/i2c/asi2c_i.py +++ b/i2c/asi2c_i.py @@ -28,7 +28,7 @@ import utime import gc from micropython import schedule -from asi2c import Channel +from asi2c import Channel, upsize # The initiator is an I2C slave. It runs on a Pyboard. I2C uses pyb for slave # mode, but pins are instantiated using machine. @@ -128,10 +128,12 @@ def _sendrx(self, rxbusy, sn=bytearray(2), txnull=bytearray(2)): if n: self.waitfor(1) # Wait for responder to request send self.own(1) # Acknowledge - mv = memoryview(self.rx_mv[0 : n]) + mv = self.lstmv[(n >> 4)] +# mv = memoryview(self.rx_mv[0 : upsize(n)]) self.i2c.recv(mv, timeout=to) self.waitfor(0) self.own(0) + self.nrx = n schedule(self._handle_rxd, mv) # Postpone allocation return True return False From 03e6f718cff55c8bab057c0c901c4a129898b061 Mon Sep 17 00:00:00 2001 From: peterhinch Date: Sat, 20 Oct 2018 18:09:36 +0100 Subject: [PATCH 2/3] Re-initialise IRQ at end of ISR (via reference) --- i2c/asi2c.py | 7 ++----- i2c/asi2c_i.py | 3 ++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/i2c/asi2c.py b/i2c/asi2c.py index 59e39ad..00838ed 100644 --- a/i2c/asi2c.py +++ b/i2c/asi2c.py @@ -160,7 +160,7 @@ class Responder(Channel): def __init__(self, i2c, pin, pinack, verbose=True): super().__init__(i2c, pinack, pin, verbose, self.rxbufsize) self._handle_rxd_ref = self._handle_rxd # Alocate RAM here - self._re_enable_ref = self._re_enable + self._handler_ref = self._handler loop = asyncio.get_event_loop() loop.create_task(self._run()) @@ -171,9 +171,6 @@ async def _run(self): await asyncio.sleep(1) gc.collect() - def _re_enable(self, _): - self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING, hard = True) - # Request was received: immediately read payload size, then payload # On Pyboard blocks for 380μs to 1.2ms for small amounts of data def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): @@ -218,5 +215,5 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): self.own(0) self.waitfor(0) self._txdone() # Invalidate source - schedule(self._re_enable_ref, 0) + self.rem.irq(handler = self._handler_ref, trigger = machine.Pin.IRQ_RISING, hard = True) # print('Time: ', utime.ticks_diff(utime.ticks_us(), tstart)) diff --git a/i2c/asi2c_i.py b/i2c/asi2c_i.py index 4586515..c8f7bdb 100644 --- a/i2c/asi2c_i.py +++ b/i2c/asi2c_i.py @@ -85,8 +85,9 @@ async def _run(self): except OSError: break await asyncio.sleep_ms(Initiator.t_poll) - self.block_max = max(self.block_max, t) # self measurement self.block_cnt += 1 + if self.block_cnt > 2: # Avoid any start-up effects + self.block_max = max(self.block_max, t) # self measurement self.block_sum += t self.nboots += 1 if self.reset is None: # No means of recovery From 2e9d7ac4ffbd61092e331be4c7f6cd828f1de345 Mon Sep 17 00:00:00 2001 From: peterhinch Date: Sun, 21 Oct 2018 11:40:44 +0100 Subject: [PATCH 3/3] Revert to soft. Pyboard responder not working. --- i2c/asi2c.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/i2c/asi2c.py b/i2c/asi2c.py index 00838ed..995c3eb 100644 --- a/i2c/asi2c.py +++ b/i2c/asi2c.py @@ -166,7 +166,7 @@ def __init__(self, i2c, pin, pinack, verbose=True): async def _run(self): await self._sync() # own pin ->0, wait for remote pin == 0 - self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING, hard = True) + self.rem.irq(handler = self._handler, trigger = machine.Pin.IRQ_RISING) #, hard = True) while True: await asyncio.sleep(1) gc.collect() @@ -176,7 +176,7 @@ async def _run(self): def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): # tstart = utime.ticks_us() # TEST addr = Responder.addr - self.rem.irq(handler = None, trigger = machine.Pin.IRQ_RISING, hard = True) + self.rem.irq(handler = None, trigger = machine.Pin.IRQ_RISING) #, hard = True) utime.sleep_us(_DELAY) # Ensure Initiator has set up to write. self.i2c.readfrom_into(addr, sn) self.own(1) @@ -215,5 +215,5 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)): self.own(0) self.waitfor(0) self._txdone() # Invalidate source - self.rem.irq(handler = self._handler_ref, trigger = machine.Pin.IRQ_RISING, hard = True) + #self.rem.irq(handler = self._handler_ref, trigger = machine.Pin.IRQ_RISING) #, hard = True) # print('Time: ', utime.ticks_diff(utime.ticks_us(), tstart)) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy