27
27
import utime
28
28
from micropython import const , schedule
29
29
import io
30
+ import gc
31
+
32
+ import micropython
33
+ micropython .alloc_emergency_exception_buf (100 )
30
34
31
35
_MP_STREAM_POLL_RD = const (1 )
32
36
_MP_STREAM_POLL_WR = const (4 )
36
40
# between Initiator setting a pin and initiating an I2C transfer: ensure
37
41
# Initiator sets up first.
38
42
_DELAY = const (20 ) # μs
43
+ # bytes objects are transmitted in blocks of size 16N where N is an integer
44
+ upsize = lambda x : (x + 15 ) & ~ 15
39
45
40
46
# Base class provides user interface and send/receive object buffers
41
47
class Channel (io .IOBase ):
@@ -52,8 +58,12 @@ def __init__(self, i2c, own, rem, verbose, rxbufsize):
52
58
self .txbyt = b'' # Data to send
53
59
self .txsiz = bytearray (2 ) # Size of .txbyt encoded as 2 bytes
54
60
self .rxbyt = b''
55
- self .rxbuf = bytearray (rxbufsize )
61
+ self .rxbuf = bytearray (upsize ( rxbufsize )) # Hold an integer no. of blocks
56
62
self .rx_mv = memoryview (self .rxbuf )
63
+ self .lstmv = []
64
+ for n in range (16 , len (self .rxbuf ) + 16 , 16 ): # Preallocate memoryviews
65
+ self .lstmv .append (self .rx_mv [0 : n ]) # for all data lengths
66
+ self .nrx = 0 # No. of bytes received (ignoring padding)
57
67
self .cantx = True # Remote can accept data
58
68
59
69
async def _sync (self ):
@@ -72,7 +82,7 @@ def waitfor(self, val): # Initiator overrides
72
82
73
83
# Get incoming bytes instance from memoryview.
74
84
def _handle_rxd (self , msg ):
75
- self .rxbyt = bytes (msg )
85
+ self .rxbyt = bytes (msg [: self . nrx ] )
76
86
77
87
def _txdone (self ):
78
88
self .txbyt = b''
@@ -122,7 +132,8 @@ def write(self, buf, off, sz):
122
132
d = buf [off : off + sz ]
123
133
d = d .encode ()
124
134
l = len (d )
125
- self .txbyt = d
135
+ # Pad to integer no. of blocks
136
+ self .txbyt = b'' .join ((d , bytes (upsize (l ) - l )))
126
137
self .txsiz [0 ] = l & 0xff
127
138
self .txsiz [1 ] = l >> 8
128
139
return l
@@ -148,19 +159,27 @@ class Responder(Channel):
148
159
rxbufsize = 200
149
160
def __init__ (self , i2c , pin , pinack , verbose = True ):
150
161
super ().__init__ (i2c , pinack , pin , verbose , self .rxbufsize )
162
+ self ._handle_rxd_ref = self ._handle_rxd # Alocate RAM here
163
+ self ._re_enable_ref = self ._re_enable
151
164
loop = asyncio .get_event_loop ()
152
165
loop .create_task (self ._run ())
153
166
154
167
async def _run (self ):
155
168
await self ._sync () # own pin ->0, wait for remote pin == 0
156
- self .rem .irq (handler = self ._handler , trigger = machine .Pin .IRQ_RISING )
169
+ self .rem .irq (handler = self ._handler , trigger = machine .Pin .IRQ_RISING , hard = True )
170
+ while True :
171
+ await asyncio .sleep (1 )
172
+ gc .collect ()
173
+
174
+ def _re_enable (self , _ ):
175
+ self .rem .irq (handler = self ._handler , trigger = machine .Pin .IRQ_RISING , hard = True )
157
176
158
177
# Request was received: immediately read payload size, then payload
159
178
# On Pyboard blocks for 380μs to 1.2ms for small amounts of data
160
179
def _handler (self , _ , sn = bytearray (2 ), txnull = bytearray (2 )):
161
180
# tstart = utime.ticks_us() # TEST
162
181
addr = Responder .addr
163
- self .rem .irq (handler = None , trigger = machine .Pin .IRQ_RISING )
182
+ self .rem .irq (handler = None , trigger = machine .Pin .IRQ_RISING , hard = True )
164
183
utime .sleep_us (_DELAY ) # Ensure Initiator has set up to write.
165
184
self .i2c .readfrom_into (addr , sn )
166
185
self .own (1 )
@@ -171,12 +190,13 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)):
171
190
if n :
172
191
self .waitfor (1 )
173
192
utime .sleep_us (_DELAY )
174
- mv = memoryview ( self .rx_mv [ 0 : n ]) # allocates
193
+ mv = self .lstmv [( n >> 4 )]
175
194
self .i2c .readfrom_into (addr , mv )
176
195
self .own (1 )
177
196
self .waitfor (0 )
178
197
self .own (0 )
179
- schedule (self ._handle_rxd , mv ) # Postpone allocation
198
+ self .nrx = n
199
+ schedule (self ._handle_rxd_ref , mv ) # Postpone allocation
180
200
181
201
self .own (1 ) # Request to send
182
202
self .waitfor (1 )
@@ -198,5 +218,5 @@ def _handler(self, _, sn=bytearray(2), txnull=bytearray(2)):
198
218
self .own (0 )
199
219
self .waitfor (0 )
200
220
self ._txdone () # Invalidate source
201
- self . rem . irq ( handler = self ._handler , trigger = machine . Pin . IRQ_RISING )
221
+ schedule ( self ._re_enable_ref , 0 )
202
222
# print('Time: ', utime.ticks_diff(utime.ticks_us(), tstart))
0 commit comments