-
Notifications
You must be signed in to change notification settings - Fork 7
Neopixel programming
Here's a brain dump from a discussion on Slack about how neopixels are programmed...
Darin Stoker 8:40 PM By the way is there any documentation on how the neopixel code works? I need to keep track of a long running buffer so I can mess with it but the buffered neopixel stuff requires working inside of an if let block, apparently. Then the write buffer command is called to show the buffer on the strip. Can I use a guard statement and write the buffer in another way so I can use functions where I pass the buffer around? If not I can create some infrastructure to wrap the regular neopixel code to get this functionality but apparently there is just some delay function for it? Delaying six microseconds appears to have an effect of some kind? That was confusing me since there is no function to fire off the write. Some kind of timed interrupt routine?
Carl 8:42 PM Yeah it’s not well enough documented. As I said in the state of the union last week, the biggest problem with S4A right bow is a lack of documentation and examples. Let me try to answer each question... 8:44 The buffered call returns the buffer as an optional to allow for the case when the MCU has run out of memory. So if you asked for a 3k neopixel buffer on a 2k device that would return a nil. 8:45 Each pixel takes 4 bytes so if you had more than 500 pixels that could easily happen. 8:48 A guard is fine but it will be somewhat hard to make it compile? Guard requires a fatal error or a return. They might not work. You can try! 8:49 The type of the neopixel buffer is listed in the documentation. In the help menu open Documentation and search for the neopixel buffer functions. You might need that for the functions you’re describing. 8:51 From memory there is a way to delete the buffer when you’re finished but generally allocations and releases of buffers should be kept to a minimum. Best if you create one buffer for the neopixels for the lifetime of your program if you can. 8:52 If you’re using buffered neopixel code, you probably don’t need the 6ms delay. It’s built in when you write the buffer.
Carl 8:53 PM I’ll do a sidebar to get into this as the reasons are a bit complicated...
9 replies
Carl 4 days ago Generally how neopixels work is you send down 24 or 32 bits for one pixel. Then the controller inside each one waits until it’s got a full set of bits (24 for standard GRB or 32 for GRBW) and there’s no more bit transmission. If this time out occurs it reads the colours, sets its LEDs accordingly and stops processing until more bits appear. If more bits appear before the timeout, the 24/32 bits it had collected are transmitted up the wire to the next pixel and it doesn’t change its colours yet but instead starts to buffer bits for the next 24/32 bits.
Carl 4 days ago The practical upshot of this is there are two ways of coding neopixels on S4A...
Carl 4 days ago In the non buffered approach, the setup function just stores a couple of internal details about the pixel configuration such as what pin they’re on and what category of neopixel they are. But setup doesn’t really do anything else. You then write pixels one by one and you have to make sure that you write them quickly, without long delays between pixel writes, or you can get an accidental early latch. Once you’ve transmitted all your pixels to the string, you just wait a short time (we chose 6ms) and they will all latch and display what they have.
Carl 4 days ago So in non buffered neopixel code the important points are 1) write out pixels quickly, 2) add a delay before you write any more pixels so the first pixels will latch.
Carl 4 days ago Buffered works differently. You get a big RAM buffer you can set up with any code you want and take as long as you need to prepare. Then you do one call to write them all out quickly at once. That included all the above rules for you.
Carl 4 days ago The buffered version might seem simpler to use but you have to be sure you’re comfortable with the amount of RAM it’s using. 4 * number of pixels is the RAM bytes taken. Check your MCU spec to see if you have enough!
Carl 4 days ago That’s also the reason the pixel count for unbuffered is a UInt16 whereas it’s a UInt8 for buffered. It’s a simple way to make sure you can’t exhaust RAM on an Arduino Uno. Although you could on an attiny. (edited)
Carl 4 days ago Buffered use is ideal for things like rolling animations or animations where you want to make the next state depend on the older states.
Carl 4 days ago Unbuffered code is maybe harder to write but less memory intensive.