geekscape / aiko_engine_mp

microPython event based engine supporting network messages (MQTT), times and various hardware drivers
Other
22 stars 24 forks source link

RGB speed #40

Closed garthk closed 3 years ago

garthk commented 3 years ago

I just hooked up 235 pixels using an 8 channel knock-off of the Adafruit 4-channel I2C-safe Bi-directional Logic Level Converter - BSS138. Such overkill for one logic line, but it's keeping the 5V supply to the strip away from the SAO port.

My booting show-off flash in #38 is doing what I'd intended: at boot time, reassure me that I've configured and wired my LEDs correctly. Reckon I might port just the flash to aiko.led for that reason. But, it's sloooow. Writing 243 updates to 7 pixels each time and then calling aiko.led.np.write again is taking 7800ms with a delay of 1ms, 7900ms with the time.sleep_ms code removed—I'm not sure why—and 1990ms even if I do nothing except call aiko.led.np.write() 243 times with 235 pixels. I'll track my work trying to speed it up here until I raise the PR.

Core loop:


def initialise():
  colours = [aiko.led.black] + [gammify(h2c(hex)) for hex in COLOURS] + [aiko.led.black]
  ncolours = len(colours)
  npixels = aiko.led.np.n
  delay = max(1, DURATION_MS // (ncolours + npixels))

  aiko.led.fill(aiko.led.black)
  aiko.led.np.write()

  before = time.ticks_ms()

  for offset in range(0 - ncolours, npixels):
    for index in range(ncolours):
      pixel = offset + index
      if 0 <= pixel < npixels:
        aiko.led.np[pixel] = colours[index]
    aiko.led.np.write()
    time.sleep_ms(delay)

  after = time.ticks_ms()
  print("took {}ms to flash {} times with delay {}ms".format(after-before, npixels+ncolours, delay))
  aiko.led.fill(aiko.led.black)
  aiko.led.np.write()
garthk commented 3 years ago

I just read the source code for NeoPixel, and I think I can come up with a few improvements. I'll report back.

garthk commented 3 years ago

Copying directly into the buffer and avoiding dot-referencing through all the modules helps: this version is within 2000ms of the 420ms required to just write the pixels.

plugins/flash_leds_on_boot.py ```python # Flash configured LEDs on boot. # Tested with 4X pixels on SAO_1, data to IO19, and configuration.led.settings = # {'zigzag': False, 'dimension': (4,), 'apa106': False, 'neopixel_pin': 19} import aiko.led import time import binascii DURATION_MS = 100 COLOURS = ["000000", "e40303", "ff8c00", "ffed00", "008026", "004dff", "750787", "000000"] def h2c(hex): return tuple(v for v in binascii.unhexlify(hex)) def initialise(): colours = [aiko.led.apply_dim(h2c(hex)) for hex in COLOURS] ncolours = len(colours) cbuf = memoryview(bytearray(3 * ncolours)) for i in range(ncolours): offset = i * 3 cbuf[offset:offset+3] = bytearray(colours[i]) buf = aiko.led.np.buf npixels = aiko.led.np.n delay = max(1, DURATION_MS // (ncolours + npixels)) lcbuf = len(cbuf) write = aiko.led.np.write sleep_ms = time.sleep_ms before = time.ticks_ms() for head in range(0 - lcbuf, len(buf), 3): trim = 0 - min(0, head) tail = head + lcbuf buf[head + trim:tail] = cbuf[trim:] write() sleep_ms(delay) after = time.ticks_ms() print("took {}ms to flash {} times with delay {}ms".format(after-before, npixels+ncolours, delay)) ```
garthk commented 3 years ago

Yeah, that'll do for now.