2

I have three libraries (is library the right word?) that I'm using in my Python code:

  • An Adafruit NeoPixels library, which comes from the rpi_281x library to control them via PWM, on GPIO pin 18.
  • One to control WS2801 Adafruit pixels (which I call "PaleoPixels" in my code. This uses SPI to write to the chips, using MOSI (GPIO pin 10) and SCLK (GPIO pin 11) pins for control.
  • A "SuperPixel" library to gang together multiple strands of both types into a super-strand, and control them with a single command set.

All of this works quite well on its own, and I can run animations at a pretty decent frame rate, if I just run a script from the terminal.

My problem seems to start when I try to use GPIO interrupts to detect button presses to trigger different LED patterns. The NeoPixels continue to work, but the SPI-driven PaleoPixels just go haywire. After a little trial and error, it seems to be related to listening for the GPIO interrupts that's somehow conflicting with the PaleoPixel control signal.

I don't have a logic analyzer, so I'm not sure exactly what's going wrong yet, but is there anything in my control script that's an obvious conflict with the SPI ontrol of the PaleoPixels, or something else I'm doing wrong with how I'm handling interrupts?

import RPi.GPIO as GPIO
import neopixel
import paleopixel
from superpixel import *

GPIO.setmode(GPIO.BCM)

GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)


# Set up the strand

# My LED strip configurations (for test):
NEOPIXEL_COUNT   = 244   # Number of NeoPixels in the strand
NEOPIXEL_PIN     = 18    # GPIO pin connected to the pixels (must support PWM!)
PALEOPIXEL_COUNT = 50    # Number of PaleoPixels in the strand

# Create pixel strands with appropriate configuration.
strand1 = neopixel.Adafruit_NeoPixel(NEOPIXEL_COUNT, NEOPIXEL_PIN)
strand2 = paleopixel.PaleoPixel(PALEOPIXEL_COUNT)

# Combine them into one SuperPixel strand
strand = SuperPixel(strand1, strand2)

# Intialize the SuperPixel strand (must be called once, before other
# functions, if the SuperPixel strand contains any NeoPixel sub-strands)
strand.begin()


# FIXME: Setting up these GPIO interrupts seems to be killing the control
#        stream to the PaleoPixels

# Set up our GPIO callbacks
def button_white(channel):
    print("button_white")
    colorAll(strand, Color(255, 0, 0))  # Set all LEDs to Red

def button_amber(channel):
    print("button_amber")
    colorAll(strand, Color(0, 255, 0))  # Set all LEDs to Green

def button_red(channel):
    print("button_red")
    colorAll(strand, Color(0, 0, 255))  # Set all LEDs to Blue

# Physical button interrupts
GPIO.add_event_detect(23, GPIO.FALLING, callback=button_white, bouncetime=300)
GPIO.add_event_detect(24, GPIO.FALLING, callback=button_amber, bouncetime=300)
GPIO.add_event_detect(25, GPIO.FALLING, callback=button_red, bouncetime=300)


# Idle loop
while 1:
    # Should I be doing something else here?
    pass

GPIO.cleanup()
3
  • The first thing to do is put a time.sleep(1) instead of pass in your while 1: loop. You'll need to add import time at the start of the script. At the moment the busy loop will use 100% CPU.
    – joan
    Commented May 9, 2016 at 19:19
  • Thanks, @joan, I'll do that, and see where things stand. Commented May 9, 2016 at 22:31
  • Whelp. That might be it. Added time.sleep(1) and the WS2801 pixels are now drawing properly. (Some glitches, but that was there before. Now I have other questions about how interrupts work, but I suppose that's for another post. @joan do you want to add that as an answer so I can mark it solved? Commented May 10, 2016 at 4:33

1 Answer 1

3

You may have identified the problem with a comment in your code.

# Idle loop
while 1:
    # Should I be doing something else here?
    pass

The while loop will be using up all the spare CPU in the "busy spin".

The only purpose of the loop is to keep the script running so that the callbacks can do their work.

Try changing the loop to:

import time
...
# Idle loop
while 1:
    time.sleep(1)

That will drop the loop CPU usage from almost 100% to almost 0%.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.