Hey all,
I have a project that I am working on which needs some fine lighting control. I determined the best tooling for the job would be a collection of (8) RGBW 8 Pixel Sticks and a Trinket M0, there is a jetson nano that will be issuing lighting commands to the trinket.
I think the best way to describe this would be the Jetson is the master and the Trinket is the slave? I'm new to i2c programming so please forgive my ignorance.
I was able to wire up the trinket and neopixels accordingly, I flashed some example code onto the trinket and the results are fantastic, everything lights up as expected, the lighting effects you can create are minded blowing and the color profiles are killer (it's my first time working with neoixels, kinda wish I did this sooner).
Where I begin to struggle is setting up the relationship between the trinket and the Jetson, if found this example code in the Pimironi Github; https://github.com/pimoroni/programming ... -neopixels, it's old and I'm having an issue flashing it to the trinket. But in addition to that, it looks like this only handles RGB neopixels and not RGBW. I'm not a C programmer, I write for the web daily, but I can see the patterns in use and I'm fairly confident through some trial and error I could extend the example code to work with RGBW.
Before I start re-inventing the wheel has anyone done this before, or at the very least know of an updated example, I might have missed in my endeavor here?
Any help is much appreciated.
TrinketM0 as i2c NeoPixel Controller
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- mcarpenterjr
- Posts: 5
- Joined: Tue Jan 01, 2019 2:35 pm
Re: TrinketM0 as i2c NeoPixel Controller
So I made some updates to the provided example from the pimoroni GitHub repo;
I swapped the TinyWireS library for Wire, which I believe should work...? I'm not sure what the diffs are between the 2 but Wire seemed to have similar functions. I haven't been able to flash the code to the trinket since I am now up against an issue with the `handleWrite` function, it get the complaint `invalid conversion from 'void (*) (uint8_t)'` I know C++ is a typed language, I'm just not sure why it would complain in this case, I can see void is being cast upon the function itself but that shouldn't affect what's being passed..?
I could be totally wrong here, again I'm not a C guy I do PHP, node and python.
Code: Select all
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
// Open this header file to configure the NeoPixel i2c driver
#include "i2c-neopixels.h"
// Neo KHZ400 is necessary on the 8Mhz Trinket
// Note: NEO_KHZ400 has been made optional in recent versions of the NeoPixel library
// please open up Adafruit_NeoPixel.h and follow the instructions inside.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN, PIXEL_COLOR_MODE + NEO_KHZ400);
// Tracks the current register pointer position and current pixel
// There are 3x as many "registers" as pixels, RGB*PIXELS
volatile uint8_t current_register = 0;
volatile uint8_t current_command = 0;
volatile uint8_t current_pixel = 0;
uint8_t r, g, b, w, x, n, o;
// Updates an individual color component according to the register position
void updatePixelColor(uint8_t value)
{
current_pixel = (uint8_t)floor(current_register / 4) % (PIXELS*4);
r = strip.getPixelColor( current_pixel ) >> 24;
g = strip.getPixelColor( current_pixel ) >> 16;
b = strip.getPixelColor( current_pixel ) >> 8;
w = strip.getPixelColor( current_pixel );
switch(current_register % 4) {
case 0: // red
strip.setPixelColor( current_pixel, value, g, b, w );
break;
case 1: // blue
strip.setPixelColor( current_pixel, r, value, b, w );
break;
case 2: // green
strip.setPixelColor( current_pixel, r, g, value, w );
break;
case 3: // white
strip.setPixelColor( current_pixel, r, g, value );
break;
}
}
// Handles each Read request
void handleRead()
{
// Each pixel has 4 components, R, G, B and W, to get the pixel index divide by 4
current_pixel = floor(current_register / 4);
uint8_t component_color = (uint8_t)( strip.getPixelColor( current_pixel ) >> (24 - ((current_register % 4)*8)) );
Wire.write(component_color);
current_register = (current_register+1) % (PIXELS*4);
}
// Handles each Write request
void handleWrite(uint8_t NumBytes)
{
// Exit if there is no data or more data than the buffer should ever allow
if (NumBytes < 1 || NumBytes > TWI_RX_BUFFER_SIZE) return;
// Always treat the first byte as the address
current_register = Wire.read();
NumBytes--;
if( current_register == 255 && NumBytes )
{
handleCommand(NumBytes);
}
else
{
// If one byte, then addr set for next read
if (!NumBytes) return;
// Loop through the remaining bytes and update the pixel components sequentially
while (NumBytes--)
{
updatePixelColor(Wire.read());
current_register++;
}
}
// Update the strip
strip.show();
}
void handleCommand(uint8_t NumBytes)
{
current_command = Wire.read();
NumBytes--;
switch(current_command){
case CMD_ALL_OFF:
for(x=0;x<PIXELS;x++){
strip.setPixelColor(x,0,0,0,0);
}
break;
case CMD_ALL_RGB:
if (NumBytes < 4) return; // Not got R G B W components
r = Wire.read();
g = Wire.read();
b = Wire.read();
w = Wire.read();
NumBytes-=4;
for(x=0;x<PIXELS;x++){
strip.setPixelColor(x,r,g,b,w);
}
break;
case CMD_SOME_RGB:
if (NumBytes < 5) return; // Not got R G B and W components
r = Wire.read();
g = Wire.read();
b = Wire.read();
w = Wire.read();
n = Wire.read();
NumBytes-=5;
o = 0; // Starting pixel
if(NumBytes)
{
o = Wire.read();
NumBytes--;
}
for(x=0;x<PIXELS-o;x++){
if(x%n == 0){
strip.setPixelColor(x+o,r,g,b,w);
}
}
break;
}
// Consume any leftover bytes
while (NumBytes--)
{
Wire.read();
}
}
void setup()
{
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onReceive(handleWrite);
Wire.onRequest(handleRead);
strip.begin();
strip.show();
}
void loop()
{
// Wire uses delay in the loop
delay(100);
}
I could be totally wrong here, again I'm not a C guy I do PHP, node and python.
- mcarpenterjr
- Posts: 5
- Joined: Tue Jan 01, 2019 2:35 pm
Re: TrinketM0 as i2c NeoPixel Controller
So I managed to get this working, I just used int instead of uint_8. Attaching the finalized stuff for later reference.
controller.ino -
i2c-neopixels.h
controller.ino -
Code: Select all
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
// Open this header file to configure the NeoPixel i2c driver
#include "i2c-neopixels.h"
// Neo KHZ400 is necessary on the 8Mhz Trinket
// Note: NEO_KHZ400 has been made optional in recent versions of the NeoPixel library
// please open up Adafruit_NeoPixel.h and follow the instructions inside.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS, PIN, PIXEL_COLOR_MODE + NEO_KHZ400);
// Tracks the current register pointer position and current pixel
// There are 3x as many "registers" as pixels, RGB*PIXELS
volatile uint8_t current_register = 0;
volatile uint8_t current_command = 0;
volatile uint8_t current_pixel = 0;
uint8_t r, g, b, w, x, n, o;
// Updates an individual color component according to the register position
void updatePixelColor(uint8_t value)
{
current_pixel = (uint8_t)floor(current_register / 4) % (PIXELS*4);
r = strip.getPixelColor( current_pixel ) >> 24;
g = strip.getPixelColor( current_pixel ) >> 16;
b = strip.getPixelColor( current_pixel ) >> 8;
w = strip.getPixelColor( current_pixel );
switch(current_register % 4) {
case 0: // red
strip.setPixelColor( current_pixel, value, g, b, w );
break;
case 1: // blue
strip.setPixelColor( current_pixel, r, value, b, w );
break;
case 2: // green
strip.setPixelColor( current_pixel, r, g, value, w );
break;
case 3: // white
strip.setPixelColor( current_pixel, r, g, value );
break;
}
}
// Handles each Read request
void handleRead()
{
// Each pixel has 4 components, R, G, B and W, to get the pixel index divide by 4
current_pixel = floor(current_register / 4);
uint8_t component_color = (uint8_t)( strip.getPixelColor( current_pixel ) >> (24 - ((current_register % 4)*8)) );
Wire.write(component_color);
current_register = (current_register+1) % (PIXELS*4);
}
// Handles each Write request
void handleWrite(int NumBytes)
{
// Exit if there is no data or more data than the buffer should ever allow
if (NumBytes < 1 || NumBytes > TWI_RX_BUFFER_SIZE) return;
// Always treat the first byte as the address
current_register = Wire.read();
NumBytes--;
if( current_register == 255 && NumBytes )
{
handleCommand(NumBytes);
}
else
{
// If one byte, then addr set for next read
if (!NumBytes) return;
// Loop through the remaining bytes and update the pixel components sequentially
while (NumBytes--)
{
updatePixelColor(Wire.read());
current_register++;
}
}
// Update the strip
strip.show();
}
void handleCommand(uint8_t NumBytes)
{
current_command = Wire.read();
NumBytes--;
switch(current_command){
case CMD_ALL_OFF:
for(x=0;x<PIXELS;x++){
strip.setPixelColor(x,0,0,0,0);
}
break;
case CMD_ALL_RGB:
if (NumBytes < 4) return; // Not got R G B W components
r = Wire.read();
g = Wire.read();
b = Wire.read();
w = Wire.read();
NumBytes-=4;
for(x=0;x<PIXELS;x++){
strip.setPixelColor(x,r,g,b,w);
}
break;
case CMD_SOME_RGB:
if (NumBytes < 5) return; // Not got R G B and W components
r = Wire.read();
g = Wire.read();
b = Wire.read();
w = Wire.read();
n = Wire.read();
NumBytes-=5;
o = 0; // Starting pixel
if(NumBytes)
{
o = Wire.read();
NumBytes--;
}
for(x=0;x<PIXELS-o;x++){
if(x%n == 0){
strip.setPixelColor(x+o,r,g,b,w);
}
}
break;
}
// Consume any leftover bytes
while (NumBytes--)
{
Wire.read();
}
}
void setup()
{
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onReceive(handleWrite);
Wire.onRequest(handleRead);
strip.begin();
strip.show();
}
void loop()
{
// Wire uses delay in the loop
delay(100);
}
Code: Select all
/************************
* VALUES YOU CAN CHANGE *
*************************/
// The I2C address that your Trinket will use
#define I2C_SLAVE_ADDRESS 0x4
// NeoPixel PIN, and pixel count
// Brightness MUST be 255 or colours can't be read back correctly from the strip
#define PIN 1 // Pin the strip is connected to
#define PIXELS 16 // Maximum of 85 pixels
#define PIXEL_COLOR_MODE NEO_GRBW // You might want to change this to NEO_RGB if you're using anything but real NeoPixels
/************************
* EVERYTHING ELSE *
*************************/
// Only change this if you have modified in TinyWireS
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 24 )
#endif
#define __AVR_ATtiny85_
// These define the commands available when writing via i2c
#define CMD_ALL_OFF 0x00
#define CMD_ALL_RGB 0x01
#define CMD_SOME_RGB 0x02
void updatePixelColor(uint8_t value);
void handleRead();
void handleWrite(uint8_t NumBytes);
void handleCommand(uint8_t NumBytes);
void setup();
void loop();
Please be positive and constructive with your questions and comments.