Page 1 of 1
Allocation when slicing memoryview instance
Posted: Tue Oct 16, 2018 12:12 pm
by pythoncoder
Am I suffering from brain-fade or is something wrong here? Tests done on a Pyboard using the onboard accelerometer as an I2C data source.
This sample works:
Code: Select all
from machine import I2C
from pyb import Timer
a = bytearray(2)
m = memoryview(a)
i = I2C(2)
def cb(_):
i.readfrom_into(60, m)
t = Timer(1, freq=1, callback=cb)
but this produces a memory error:
Code: Select all
from machine import I2C
from pyb import Timer
a = bytearray(10)
m = memoryview(a)
i = I2C(2)
def cb(_):
i.readfrom_into(60, m[0:2])
t = Timer(1, freq=1, callback=cb)
The callback works in that if I issue
cb(0) at the REPL: the first two bytes of the 10 byte array are updated. A
memoryview lets you take a slice into the original data without copying. So why is memory allocated?
Re: machine.I2C: allocation reading into pre-allocated buffer
Posted: Tue Oct 16, 2018 12:29 pm
by Roberthh
I am also confused by the follwing, which I stumbled over a few days (or weeks) ago, and which did not meet my expectation:
Code: Select all
>>> s="1234567890"
>>> m=memoryview(s)
>>> m[0:2]
<memoryview>
>>> m[0]
49
>>> x=m[0:2]
>>> x
<memoryview>
>>> s[0:2]
'12'
>>> for _ in m[0:2]:
... _
...
49
50
I expeceted m[0:2] to return the same as s[0:2]. Iterating through m it is however possible, but not slicing.
Re: machine.I2C: allocation reading into pre-allocated buffer
Posted: Tue Oct 16, 2018 12:50 pm
by pythoncoder
A slice of a
memoryview returns another
memoryview. A
memoryview instance doesn't have the methods of the object it's based on, so there aren't many things you can do with it. Thus
Code: Select all
>>> a = b'the quick brown fox'
>>> a.find(b'q')
4
>>> m = memoryview(a)
>>> m.find(b'q')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'memoryview' object has no attribute 'find'
>>>
You can cast it to the original type, but then you're creating a copy which normally defeats the object.
Code: Select all
a = bytearray(20)
m = memoryview(a)
m1 = m[1:3] # m1 is another memoryview instance. Still points into the original bytearray.
b = bytearray(m1) # b has the attributes of a bytearray. But it's a new instance.
This is true for CPython and MicroPython.
This fails too. OK, I've got it.
Posted: Tue Oct 16, 2018 1:05 pm
by pythoncoder
Code: Select all
from machine import I2C
from pyb import Timer
a = bytearray(10)
m = memoryview(a)
b = bytearray((1,2))
def cb(_):
m[3:5] = b
t = Timer(1, freq=1, callback=cb)
So the problem has nothing to do with I2C but with memoryview slicing.
[EDIT]
I've answered my own question: m[x:y] creates a new
memoryview object on the heap. This implies it's impossible (in an interrupt context) to use
I2C.readfrom_into to populate a circular buffer.
In any event I've come up with a better solution for my application.
Re: Allocation when slicing memoryview instance
Posted: Tue Oct 16, 2018 4:13 pm
by jickster
Until scoped allocation is implemented.
Sent from my iPhone using Tapatalk Pro
Re: Allocation when slicing memoryview instance
Posted: Tue Oct 16, 2018 5:45 pm
by pythoncoder
Indeed. It does seem unfortunate that
memoryview objects in particular use the heap. I have raised
this RFC with a minimal test case. I'll be interested to see the response.