What I mean is that, if for instance, for WS2812 the timings are
symbol "1" --> 660nsec High + 330 nsec low --> 2 basic period HIGH + 1 basic period LOW (let's define a "basic" as a 330nsec period)
symbol "0" --> 330nsec high + 660 nsec low --> 1 basic period HIGH + 2 basic period LOW
Suppose we have N leds. For each one we need 24 bits (as in APA102). The trick is to convert these 24*N "WS2812 bits" to 3*24*N SPI bits
For instance, if the sequence to be sent is
11010011....
We previously prepare the frame buffer converting them to (each 3 bits here will correspond to one original bit)
110 110 100 110 100 100 110 110 ..... ---> grouping them into bytes --> 0xDA 0x69 0x36 ....
Then we set up the HSPI clock to 3MHz we give it the buffer and it automatically sends it. When it finishes we send the following bytes.
As the HSPI in ESP8266 can be, as much, 20bytes, I would limit it to 18 bytes, which would allow us for 2 "complete" leds
18 [bytes]*8 [spi_bits/byte]/3[spi_bits/neopixel_bit])/24 [neopixel_bit/led] --> 2 leds
View attachment 44261
yes should work.so if I am to emulate the serial protocol needed, a simple timer with flag to determine if its a "1" or a "0", or make use of the delay keyword will do the trick?!
Unfortunately this is not so simple! At least not with Arduino. This protocol is very tricky the data must be send at a very high rate (800 kHz or 1.25 us). If there is a delay longer than around 10us it reset and start over to the first LED. So your solution won't be able to address more than 1 LED. Look at this timing table.why slow? I guess the trick will be to build the complete "image" string before hand, and send all the bytes with a timer...
I'm thinking of animated gifs that could be played in a "screen" of addressable leds...
I think so: unless I am totally wrong about these ledsSo, to create an image, I only need to send the data once, and only send if I need to change?
If you want to change whatever pixel, you must refresh the whole arrayAnother question... In an array of say 20 leds... and I only want to change a middle one, like the 11th led... is it possible?
If you want to change whatever pixel, you must refresh the whole array
#include <Adafruit_NeoPixel.h>
#define PIN 5
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(66, PIN, NEO_GRB + NEO_KHZ800); // number of WS2812B LEDs on strip, green-red-blue, 800khz
void setup() {
// init serial
Serial.begin(9600);
// init WS2812B LED strips
strip1.begin();
strip1.setBrightness(127);
strip1.show();
}
void loop() {
for (int i = 0; i < 67; i++){
strip1.setPixelColor(i,255,0,0); // sets the color of each LED
delay(40); strip1.show();
}
}
//WS2812 Driver Function
void RGB_update(int LED, byte RED, byte GREEN, byte BLUE) {
// LED is the LED number starting with 0
// RED, GREEN, BLUE is the brightness 0..255 setpoint for that LED
byte ExistingPort, WS2812pinHIGH;//local variables here to speed up pinWrites
if(LED>=0){//map the REG GREEN BLUE Values into the RGB[] array
RGB[LED * 3] = GREEN;
RGB[LED * 3 + 1] = RED;
RGB[LED * 3 + 2] = BLUE;
}
noInterrupts();//kill the interrupts while we send the bit stream out...
ExistingPort = PORTB; // save the status of the entire PORT B - let's us write to the entire port without messing up the other pins on that port
WS2812pinHIGH = PORTB | 1; //this gives us a byte we can use to set the whole PORTB with the WS2812 pin HIGH
int bitStream = numberOfLEDs * 3;//total bytes in the LED string
//This for loop runs through all of the bits (8 at a time) to set the WS2812 pin ON/OFF times
for (int i = 0; i < bitStream; i++) {
PORTB = WS2812pinHIGH;//bit 7 first, set the pin HIGH - it always goes high regardless of a 0/1
//here's the tricky part, check if the bit in the byte is high/low then right that status to the pin
// (RGB[i] & B10000000) will strip away the other bits in RGB[i], so here we'll be left with B10000000 or B00000000
// then it's easy to check if the bit is high or low by AND'ing that with the bit mask ""&& B10000000)"" this gives 1 or 0
// if it's a 1, we'll OR that with the Existing port, thus keeping the pin HIGH, if 0 the pin is written LOW
PORTB = ((RGB[i] & B10000000) && B10000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//these are NOPS - these let us delay clock cycles for more precise timing
PORTB = ExistingPort;//okay, here we know we have to be LOW regardless of the 0/1 bit state
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//minimum LOW time for pin regardless of 0/1 bit state
// then do it again for the next bit and so on... see the last bit though for a slight change
PORTB = WS2812pinHIGH;//bit 6
PORTB = ((RGB[i] & B01000000) && B01000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 5
PORTB = ((RGB[i] & B00100000) && B00100000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 4
PORTB = ((RGB[i] & B00010000) && B00010000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 3
PORTB = ((RGB[i] & B00001000) && B00001000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 2
PORTB = ((RGB[i] & B00000100) && B00000100) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 1
PORTB = ((RGB[i] & B00000010) && B00000010) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 0
__asm__("nop\n\t");//on this last bit, the check is much faster, so had to add a NOP here
PORTB = ((RGB[i] & B00000001) && B00000001) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;//note there are no NOPs after writing the pin LOW, this is because the FOR Loop uses clock cycles that we can use instead of the NOPS
}//for loop
interrupts();//enable the interrupts
// all done!
}//void RGB_update
#IgnoreWarnings: 9
#Region Project Attributes
#AutoFlushLogs: True
#CheckArrayBounds: True
#StackBufferSize: 300
#End Region
Sub Process_Globals
'These global variables will be declared once when the application starts.
'Public variables can be accessed from all modules.
Public Serial1 As Serial
Public pin8 As Pin
Private LED As Int
Private RED,GREEN,BLUE As Byte
End Sub
Private Sub AppStart
Serial1.Initialize(115200)
Log("AppStart")
LED = 20
RED = 255
GREEN = 255
BLUE = 0
pin8.Initialize(8,pin8.MODE_OUTPUT)
' pin8.Mode = pin8.MODE_OUTPUT
RunNative("RGB_update", Null)
End Sub
#if C
//VARIABLES AND DEFINES HERE - NEEDED BY THE WS2812 DRIVER CODE
//#define WS2812_pin 8 // only digital pin 8 works right now //Defined in B4R
#define numberOfLEDs 40// total number of RGB LEDs
byte RGB[120];//take your number of LEDs and multiply by 3
// FUNCTIONS HERE
//void RGB_update(int LED, byte RED, byte GREEN, byte BLUE);//function to drive LEDs //I don't think we need this here(?)
//void setup() {
//pinMode(WS2812_pin, OUTPUT); //Defined in B4R
//}//setup
//void loop() {
//RGB_update(0,0,0,0);//LED#, RED, GREEN, BLUE
//delay(1000);
//}//loop
//WS2812 Driver Function
//void RGB_update(int LED, byte RED, byte GREEN, byte BLUE) {
void RGB_update(B4R::Object* o) {
// LED is the LED number starting with 0
// RED, GREEN, BLUE is the brightness 0..255 setpoint for that LED
byte ExistingPort, WS2812pinHIGH;//local variables here to speed up pinWrites
if(b4r_main::_led>=0){//map the RED GREEN BLUE Values into the RGB[] array
RGB[ b4r_main::_led * 3] = b4r_main::_green;
RGB[ b4r_main::_led * 3 + 1] = b4r_main::_red;
RGB[ b4r_main::_led * 3 + 2] = b4r_main::_blue;
}
noInterrupts();//kill the interrupts while we send the bit stream out...
ExistingPort = PORTB; // save the status of the entire PORT B - let's us write to the entire port without messing up the other pins on that port
WS2812pinHIGH = PORTB | 1; //this gives us a byte we can use to set the whole PORTB with the WS2812 pin HIGH
int bitStream = numberOfLEDs * 3;//total bytes in the LED string
//This for loop runs through all of the bits (8 at a time) to set the WS2812 pin ON/OFF times
for (int i = 0; i < bitStream; i++) {
PORTB = WS2812pinHIGH;//bit 7 first, set the pin HIGH - it always goes high regardless of a 0/1
//here's the tricky part, check if the bit in the byte is high/low then right that status to the pin
// (RGB[i] & B10000000) will strip away the other bits in RGB[i], so here we'll be left with B10000000 or B00000000
// then it's easy to check if the bit is high or low by AND'ing that with the bit mask ""&& B10000000)"" this gives 1 or 0
// if it's a 1, we'll OR that with the Existing port, thus keeping the pin HIGH, if 0 the pin is written LOW
PORTB = ((RGB[i] & B10000000) && B10000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//these are NOPS - these let us delay clock cycles for more precise timing
PORTB = ExistingPort;//okay, here we know we have to be LOW regardless of the 0/1 bit state
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");//minimum LOW time for pin regardless of 0/1 bit state
// then do it again for the next bit and so on... see the last bit though for a slight change
PORTB = WS2812pinHIGH;//bit 6
PORTB = ((RGB[i] & B01000000) && B01000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 5
PORTB = ((RGB[i] & B00100000) && B00100000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 4
PORTB = ((RGB[i] & B00010000) && B00010000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 3
PORTB = ((RGB[i] & B00001000) && B00001000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 2
PORTB = ((RGB[i] & B00000100) && B00000100) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 1
PORTB = ((RGB[i] & B00000010) && B00000010) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 0
__asm__("nop\n\t");//on this last bit, the check is much faster, so had to add a NOP here
PORTB = ((RGB[i] & B00000001) && B00000001) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;//note there are no NOPs after writing the pin LOW, this is because the FOR Loop uses clock cycles that we can use instead of the NOPS
}//for loop
interrupts();//enable the interrupts
// all done!
}//void RGB_update
#end if
'Original Function Creator : Kevin Darrah
'B4R Code Module Adaptation : Cableguy
'Usage:
'I Think it could not be simpler...
'Initialize it passing the amout of LEDs in your array
'In this Module, down in the C code block, change "byte RGB[120];", changing the size of this array to be 3 times the amount of leds passed in the initializer
'Call "SetLed" passing the Led number and the RGB values to set it to
'That's it!!!
Sub Process_Globals
Private PIN8 As Pin
Private LED As Int
Private RED As Byte
Private GREEN As Byte
Private BLUE As Byte
Private NLEDs As Int
End Sub
Public Sub Initialize(NumberOfLEDS As Int)
PIN8.Initialize(8, PIN8.MODE_OUTPUT)
NLEDs = NumberOfLEDS
End Sub
Public Sub SetLed(LEDNumber As Int, R As Byte, G As Byte, B As Byte)
RED = R
GREEN = G
BLUE = B
LED = LEDNumber
If LED = -1 Then
Log("all lit")
Log(NLEDs)
For n = 0 To NLEDs-1
LED=n
RunNative("RGB_update", Null)
Next
Else
RunNative("RGB_update", Null)
End If
End Sub
#if C
#define numberOfLEDs b4r_ws2812b::_nleds
byte RGB[120];//take your number of LEDs and multiply by 3 ! THIS IS VERY IMPORTANT!!!
void RGB_update(B4R::Object* o) {
byte ExistingPort, WS2812pinHIGH;
if(b4r_ws2812b::_led >=0){
RGB[ b4r_ws2812b::_led * 3] = b4r_ws2812b::_green;
RGB[ b4r_ws2812b::_led * 3 + 1] = b4r_ws2812b::_red;
RGB[ b4r_ws2812b::_led * 3 + 2] = b4r_ws2812b::_blue;
}
noInterrupts();
ExistingPort = PORTB;
WS2812pinHIGH = PORTB | 1;
int bitStream = numberOfLEDs * 3;
for (int i = 0; i < bitStream; i++) {
PORTB = WS2812pinHIGH;//bit 7 first, set the pin HIGH - it always goes high regardless of a 0/1
PORTB = ((RGB[i] & B10000000) && B10000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 6
PORTB = ((RGB[i] & B01000000) && B01000000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 5
PORTB = ((RGB[i] & B00100000) && B00100000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 4
PORTB = ((RGB[i] & B00010000) && B00010000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 3
PORTB = ((RGB[i] & B00001000) && B00001000) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 2
PORTB = ((RGB[i] & B00000100) && B00000100) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 1
PORTB = ((RGB[i] & B00000010) && B00000010) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = WS2812pinHIGH;//bit 0
__asm__("nop\n\t");
PORTB = ((RGB[i] & B00000001) && B00000001) | ExistingPort;
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
PORTB = ExistingPort;
}
interrupts();
}
#end if
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?