bytearray objects use too much memory?

Questions and discussion about running MicroPython on a micro:bit board.
Target audience: MicroPython users with a micro:bit.
Post Reply
windy54
Posts: 14
Joined: Thu May 28, 2015 8:01 pm

bytearray objects use too much memory?

Post by windy54 » Tue Nov 26, 2019 4:59 pm

There is a small chance I have found a problem with the way bytearray objects are created on the microbit.

Background: I purchased a http://rasp.io/inspiring/ set of leds when the kickstarter was launched a couple of years ago.

They are basically SK9822 leds in various shapes, straight 8, triangle of 24 and circle of 24 leds, like neopixels but these use the SPI interface.

For the PI a python library was created, https://github.com/windy54/raspio-inspi ... ter/apa.py

I ported this across to the microbit https://github.com/windy54/raspio-inspi ... spiring.py

It works on the microbit for up to 64 leds, as soon as I select 65 the software crashes. After some investigation it runs out of memory on the line self.led_values in the original code snippet below.

Code: Select all

class Apa(object):
    def __init__(self, numleds):
        self.numleds = numleds
        self.led_values = [] # initialise a list for LED values
        for y in range(numleds):
            self.led_values.append([0xE0, 0x00, 0x00, 0x00])
After some searching on the web I came across a post which suggested using bytearray as below

Code: Select all

class Apa:
    def __init__(self, num_leds):
        self.buffer = bytearray(4)
        self.leds = [array.array('b',[0xE0, 0, 0x0, 0]) for i in range(num_leds)]
This code still fails in the same manner.

I tried the same construct on a PI to see how much memory is used for each element and it seems to be
32 + num_leds*4 bytes. Which is what I expected, i.e. 32 bytes as reference for the object and 4 bytes per element.

On the microbit it seems to use 32 bytes per element. I used memfree() to monitor the memory and with 64 leds there is about 20 bytes left, 65 causes the crash when it runs out of memory.

Apologies for the length of the post, I thought it important to show what I have been doing.

I guess my questions are:
  • Is there something wrong with the code, a better way to create the self.led_values?
    Have I found a bug in the microbit micropython code?
I think I found the micropython source for the microbit but it was beyond my understanding to determine what is going on.

Thanks to another post on the web I have managed to control 136 leds from a microbit. https://github.com/windy54/raspio-inspi ... piring2.py
windy54

lujo
Posts: 24
Joined: Sat May 11, 2019 2:30 pm

Re: bytearray objects use too much memory?

Post by lujo » Tue Nov 26, 2019 11:43 pm

HI,

With 144 APA102 LEDs (a 1m Dotstar strip):

Code: Select all

from microbit import *

spi.init(baudrate=4000000, mode=0, sclk=pin14, mosi=pin8)

leds = 144
buf = bytearray(4 + leds * 4 + (leds // 16 + 1))

for i in range(leds):
    buf[4 + i * 4    ] = 0xe0
    buf[4 + i * 4 + 1] = 0x04   # blue
    buf[4 + i * 4 + 2] = 0x00   # green
    buf[4 + i * 4 + 3] = 0x00   # red
spi.write(buf)

while True:
    if button_a.was_pressed():
        for i in range(leds):
            buf[4 + i * 4] = 0xe7   # leds on
        spi.write(buf)
    if button_b.was_pressed():
        for i in range(leds):
            buf[4 + i * 4] = 0xe0   # leds off
        spi.write(buf)
lujo

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: bytearray objects use too much memory?

Post by jimmo » Wed Nov 27, 2019 12:51 am

Your code isn't really using bytearrays other than for self.buffer. self.leds is a list of arrays, and creates a large number of small objects. bytearrays themselves are quite efficient (16-byte object metadata, plus one byte per actual byte). In your code, it ends up creating a large number of small objects in order to create the final list, and nothing can be freed until the very end.

You just want something like

Code: Select all

self.leds = bytearray(4 + num_leds*4 + 4)
(I'm assuming this is like APA102 where you have a four byte start and end sequence).

Then you can access an individual LED with

Code: Select all

self.leds[n * 4 + 4 + 0] = brightness
self.leds[n * 4 + 4 + 1] = blue
self.leds[n * 4 + 4 + 2] = green
self.leds[n * 4 + 4 + 3] = red

windy54
Posts: 14
Joined: Thu May 28, 2015 8:01 pm

Re: bytearray objects use too much memory?

Post by windy54 » Wed Nov 27, 2019 10:40 am

Thanks for the responses, I went with Jimmo's suggestion and have managed to control 136 leds without it crashing.

On to my next problem.

Steve

Post Reply