chipKIT® Development Platform

Inspired by Arduino™

Fubarino SD-->WS2812b LED RGB- HELP- CODE

Created Tue, 29 Apr 2014 17:07:08 +0000 by Omnimusha


Omnimusha

Tue, 29 Apr 2014 17:07:08 +0000

HELLO, I HAVE TRIED THIS CODE AND WORKS IN ARDUINO UNO, But I fubarino sd does not work.

anyone can help me fix this code?, or someone has another code to operate this ws2812b?

//http://partfusion.com/products/sewrgb-v0/

#define SEWRGB_PIN 6
//#define SEWRGB_PIN 12

#define LED_COUNT 1
uint8_t leds[LED_COUNT][3];

void setup() {
  pinMode(SEWRGB_PIN, OUTPUT);
  digitalWrite(SEWRGB_PIN, LOW);
}

#define DOBIT(_bit) do { \
  if ((_bit)) { \
    *out |= bit; \
    *out |= bit; \
    *out |= bit; \
    *out &= ~bit; \
    *out &= ~bit; \
  } else { \
    *out |= bit; \
    *out &= ~bit; \
    *out &= ~bit; \
    *out &= ~bit; \
    *out &= ~bit; \
  } \
} while (0);
#define DOBYTE(_byte) do { \
  const uint8_t __byte = (_byte); \
  DOBIT((__byte) & 0b10000000); \
  DOBIT((__byte) & 0b01000000); \
  DOBIT((__byte) & 0b00100000); \
  DOBIT((__byte) & 0b00010000); \
  DOBIT((__byte) & 0b00001000); \
  DOBIT((__byte) & 0b00000100); \
  DOBIT((__byte) & 0b00000010); \
  DOBIT((__byte) & 0b00000001); \
} while (0);
#define DORGB(_r,_g,_b) do { \
  DOBYTE(_g); \
  DOBYTE(_r); \
  DOBYTE(_b); \
} while (0);

void show(const uint8_t pin) {
  const uint8_t bit = digitalPinToBitMask(pin);
  const uint8_t port = digitalPinToPort(pin);
  volatile uint8_t * out = portOutputRegister(port);
  *out &= ~bit;

  noInterrupts();
  for (int i = 0; i < LED_COUNT; i++) {
    DORGB(leds[i][0], leds[i][1], leds[i][2]);
  }
  *out &= ~bit;
  interrupts();
}

void setpixel(const int index, const uint8_t r, const uint8_t g, const uint8_t b) {
  leds[index][0] = r;
  leds[index][1] = g;
  leds[index][2] = b;
}
void fill(const uint8_t r, const uint8_t g, const uint8_t b) {
  for (int i = 0; i < LED_COUNT; i++) {
    setpixel(i, r, g, b);
  }
}

void loop() {
  const uint8_t ONE = 0b00111111;
  const uint8_t ZERO = 0b00000000;
  const int DELAY = 2000;

  fill(ONE, ZERO, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ONE, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ZERO, ONE);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ONE, ONE, ONE);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ZERO, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);
}

[url]http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Components/LED/WS2812.pdf[/url]

[url]https://learn.sparkfun.com/tutorials/ws2812-breakout-hookup-guide/all[/url]


EmbeddedMan

Tue, 29 Apr 2014 17:19:45 +0000

Can you describe more about what doesn't work about it? Does it compile? If not, what error messages does it give? If so, does it run? If not, what happens, exactly?

*Brian


Omnimusha

Tue, 29 Apr 2014 17:41:16 +0000

not compiled, here, changing, volatile uint8_t * out = portOutputRegister (port);

to volatile uint32_t * out = portOutputRegister (port);

but behaves strange the LED, malfunctioning.

other question is that the LEDs are alimetados to 5v, the input pin of the LED: Control data input signal. **What voltage should be? **arduino 5v feeds and fubarino with 3.15V


[url]https://github.com/adafruit/Adafruit_NeoPixel[/url] this library in arduino operates WS2812B.

in Fubarino sd, with the ide, mpide-0023-windows-20131118-test, compiles, but WS2812B not work.

please help


EmbeddedMan

Tue, 29 Apr 2014 19:08:56 +0000

As long as you power the LED with 5V, your 3.3V (or 3.15V) digital control signal input voltage should be fine.

I think the problem will lie in that the LED is very sensitive to the exact duration of the low and high parts of the pulses you send out. Because the Fubarino is so much faster than an Arduino, the code as written for the Arduino will run too fast, and the LEDs won't get proper control information.

You're going to need to either find a chipKIT library for this LED, or get or your scope (or logic analyzer) and add some delays in the right place in the library to slow down the pulses so that they match what the LED datasheet says.

*Brian


Omnimusha

Tue, 29 Apr 2014 19:26:08 +0000

I do not find informción sobew these functions:

digitalPinToBitMask(pin); digitalPinToPort(pin); portOutputRegister(port);


Arduino**************** volatile uint8_t * out = portOutputRegister(port); *out &= ~bit;

here in Arduino define uint8_t * out and Sd Fubarino uint32_t * out make a difference?


Fubarino Sd********

volatile uint32_t * out = portOutputRegister(port); *out &= ~bit;


jmlynesjr

Tue, 29 Apr 2014 20:20:19 +0000

Get a copy of Circuit Cellar Magazine April 2014, Issue 285.

Look at page 66 "From the Bench - Programmable RGB LED Strips" by Jeff Bachiochi.

As EmbeddedMan said and Jeff details in his article, these things have very strict timing requirements.

James


Omnimusha

Tue, 29 Apr 2014 20:36:12 +0000

I found only up to page 18.

look at this, that explain how to operate it, but do not understand as aducuarte this to Fubarino Sd

[url]http://www.instructables.com/id/Bitbanging-step-by-step-Arduino-control-of-WS2811-/all/?lang=es[/url]

/*---------------------------------------------------------------------
  Acrobotic - 01/10/2013
  Author: x1sc0 
  Platforms: Arduino Uno R3
  File: bitbang_whitish.ino

  Description: 
  This code sample accompanies the "How To Control 'Smart' RGB LEDs: 
  WS2811, WS2812, and WS2812B (Bitbanging Tutorial)" Instructable 
  (http://www.instructables.com/id/Bitbanging-step-by-step-Arduino-control-of-WS2811-/) 
  
  The code illustrates how to continuously set one WS2811 (driver)/
  WS2812/WS2812B RGB LEDs to a full intensity whitish.  The color and 
  number of WS281X ICs can be easily modified to explore the full range of
  these wonderful family of LEDs.
  
  The communication is done by bitbanging a self-clocked 800KHz, NZR signal.  
  The implementation was done using assembly so that the timing of the signal 
  was extremely accurate.

  Usage:
  Connect power (5V), ground (GND), and the Arduino Uno pin defined 
  by DIGITAL_PIN to the WS281X ports VCC, GND, and DIN ports, respectively.

  Upload the program to an Arduino Uno, and the Green LED of the first 
  WS281X will light up to full brightness. 

  ------------------------------------------------------------------------
  For a full-blown Arduino library, check out:
  https://github.com/acrobotic/Ai_Library_WS281X/
  ------------------------------------------------------------------------
  Please consider buying products from Acrobotic to help fund future
  Open-Source projects like this! We’ll always put our best effort in every
  project, and release all our design files and code for you to use. 
  http://acrobotic.com/
  ------------------------------------------------------------------------

  License:
  Beerware License; if you find the code useful, and we happen to cross 
  paths, you're encouraged to buy us a beer. The code is distributed hoping
  that you in fact find it useful, but  without warranty of any kind.
------------------------------------------------------------------------*/

#define NUM_RGB       (1)         // Number of WS281X we have connected
#define NUM_BYTES     (NUM_RGB*3) // Number of LEDs (3 per each WS281X)
#define DIGITAL_PIN   (8)         // Digital port number
#define PORT          (PORTB)     // Digital pin's port
#define PORT_PIN      (PORTB0)    // Digital pin's bit position
#define R             (255)        // Intensity of Red LED
#define G             (255)        // Intensity of Green LED
#define B             (255)        // Intensity of Blue LED

#define NUM_BITS      (8)         // Constant value: bits per byte

uint8_t* rgb_arr = NULL;
uint32_t t_f;

void setup() 
{
  pinMode(DIGITAL_PIN,OUTPUT);
  digitalWrite(DIGITAL_PIN,0);
  if((rgb_arr = (uint8_t *)malloc(NUM_BYTES)))             
  {                 
    memset(rgb_arr, 0, NUM_BYTES);                         
  }        
  render();
}

void loop() 
{
  int i;
  for(i=0;i<NUM_RGB;i++)
    setColorRGB(i,R,G,B);
  render();
  delay(1000);
}

void setColorRGB(uint16_t idx, uint8_t r, uint8_t g, uint8_t b) 
{
  if(idx < NUM_RGB) 
  {
    uint8_t *p = &rgb_arr[idx*3]; 
    *p++ = g;  
    *p++ = r;
    *p = b;
  }
}

void render(void) 
{
  if(!rgb_arr) return;

  while((micros() - t_f) < 50L);  // wait for 50us (data latch)

  cli(); // Disable interrupts so that timing is as precise as possible
  volatile uint8_t  
   *p    = rgb_arr,   // Copy the start address of our data array
    val  = *p++,      // Get the current byte value & point to next byte
    high = PORT |  _BV(PORT_PIN), // Bitmask for sending HIGH to pin
    low  = PORT & ~_BV(PORT_PIN), // Bitmask for sending LOW to pin
    tmp  = low,       // Swap variable to adjust duty cycle 
    nbits= NUM_BITS;  // Bit counter for inner loop
  volatile uint16_t
    nbytes = NUM_BYTES; // Byte counter for outer loop
  asm volatile(
  // The volatile attribute is used to tell the compiler not to optimize 
  // this section.  We want every instruction to be left as is.
  //
  // Generating an 800KHz signal (1.25us period) implies that we have
  // exactly 20 instructions clocked at 16MHz (0.0625us duration) to 
  // generate either a 1 or a 0---we need to do it within a single 
  // period. 
  // 
  // By choosing 1 clock cycle as our time unit we can keep track of 
  // the signal's phase (T) after each instruction is executed.
  //
  // To generate a value of 1, we need to hold the signal HIGH (maximum)
  // for 0.8us, and then LOW (minimum) for 0.45us.  Since our timing has a
  // resolution of 0.0625us we can only approximate these values. Luckily, 
  // the WS281X chips were designed to accept a +/- 300ns variance in the 
  // duration of the signal.  Thus, if we hold the signal HIGH for 13 
  // cycles (0.8125us), and LOW for 7 cycles (0.4375us), then the variance 
  // is well within the tolerated range.
  //
  // To generate a value of 0, we need to hold the signal HIGH (maximum)
  // for 0.4us, and then LOW (minimum) for 0.85us.  Thus, holding the
  // signal HIGH for 6 cycles (0.375us), and LOW for 14 cycles (0.875us)
  // will maintain the variance within the tolerated range.
  //
  // For a full description of each assembly instruction consult the AVR
  // manual here: http://www.atmel.com/images/doc0856.pdf
    // Instruction        CLK     Description                 Phase
   "nextbit:\n\t"         // -    label                       (T =  0) 
    "sbi  %0, %1\n\t"     // 2    signal HIGH                 (T =  2) 
    "sbrc %4, 7\n\t"      // 1-2  if MSB set                  (T =  ?)          
     "mov  %6, %3\n\t"    // 0-1   tmp'll set signal high     (T =  4) 
    "dec  %5\n\t"         // 1    decrease bitcount           (T =  5) 
    "nop\n\t"             // 1    nop (idle 1 clock cycle)    (T =  6)
    "st   %a2, %6\n\t"    // 2    set PORT to tmp             (T =  8)
    "mov  %6, %7\n\t"     // 1    reset tmp to low (default)  (T =  9)
    "breq nextbyte\n\t"   // 1-2  if bitcount ==0 -> nextbyte (T =  ?)                
    "rol  %4\n\t"         // 1    shift MSB leftwards         (T = 11)
    "rjmp .+0\n\t"        // 2    nop nop                     (T = 13)
    "cbi   %0, %1\n\t"    // 2    signal LOW                  (T = 15)
    "rjmp .+0\n\t"        // 2    nop nop                     (T = 17)
    "nop\n\t"             // 1    nop                         (T = 18)
    "rjmp nextbit\n\t"    // 2    bitcount !=0 -> nextbit     (T = 20)
   "nextbyte:\n\t"        // -    label                       -
    "ldi  %5, 8\n\t"      // 1    reset bitcount              (T = 11)
    "ld   %4, %a8+\n\t"   // 2    val = *p++                  (T = 13)
    "cbi   %0, %1\n\t"    // 2    signal LOW                  (T = 15)
    "rjmp .+0\n\t"        // 2    nop nop                     (T = 17)
    "nop\n\t"             // 1    nop                         (T = 18)
    "dec %9\n\t"          // 1    decrease bytecount          (T = 19)
    "brne nextbit\n\t"    // 2    if bytecount !=0 -> nextbit (T = 20)
    ::
    // Input operands         Operand Id (w/ constraint)
    "I" (_SFR_IO_ADDR(PORT)), // %0
    "I" (PORT_PIN),           // %1
    "e" (&PORT),              // %a2
    "r" (high),               // %3
    "r" (val),                // %4
    "r" (nbits),              // %5
    "r" (tmp),                // %6
    "r" (low),                // %7
    "e" (p),                  // %a8
    "w" (nbytes)              // %9
  );
  sei();                          // Enable interrupts
  t_f = micros();                 // t_f will be used to measure the 50us 
                                  // latching period in the next call of the 
                                  // function.
}

jmlynesjr

Tue, 29 Apr 2014 21:09:06 +0000

Look at:

ftp://ftp.circuitcellar.com/pub/Circuit_Cellar/2014/285/285-Bachiochi.zip

for Jeff's test code. Assembly language for a PIC18F26J50.

James


Omnimusha

Tue, 29 Apr 2014 21:17:06 +0000

this encoding is very advanced for my


jmlynesjr

Tue, 29 Apr 2014 22:40:21 +0000

You can order a pdf of the issue for $9.00 USD from the Circuit Cellar site. They don't list individual articles for sale.

James


Omnimusha

Wed, 30 Apr 2014 02:09:40 +0000

//http://partfusion.com/products/sewrgb-v0/

#define SEWRGB_PIN 6
//#define SEWRGB_PIN 12

#define LED_COUNT 1
uint8_t leds[LED_COUNT][3];

void setup() {
  Serial.begin(9600);
  pinMode(SEWRGB_PIN, OUTPUT);
  digitalWrite(SEWRGB_PIN, LOW);
}

#define DOBIT(_bit) do { \
  if ((_bit)) { \
    *out |= bit; \
    *out |= bit; \
    *out |= bit; \
    *out &= ~bit; \
    *out &= ~bit; \
  } else { \
    *out |= bit; \
    *out &= ~bit; \
    *out &= ~bit; \
    *out &= ~bit; \
    *out &= ~bit; \
  } \
} while (0);
#define DOBYTE(_byte) do { \
  const uint8_t __byte = (_byte); \
  DOBIT((__byte) & 0b10000000); \
  DOBIT((__byte) & 0b01000000); \
  DOBIT((__byte) & 0b00100000); \
  DOBIT((__byte) & 0b00010000); \
  DOBIT((__byte) & 0b00001000); \
  DOBIT((__byte) & 0b00000100); \
  DOBIT((__byte) & 0b00000010); \
  DOBIT((__byte) & 0b00000001); \
} while (0);
#define DORGB(_r,_g,_b) do { \
  DOBYTE(_g); \
  DOBYTE(_r); \
  DOBYTE(_b); \
} while (0);

void show(const uint8_t pin) {
  const uint8_t bit = digitalPinToBitMask(pin);
  const uint8_t port = digitalPinToPort(pin);
  volatile uint8_t * out = portOutputRegister(port);
  uint8_t data=  *out;
  Serial.println(data,BIN);
  Serial.println(data,DEC);
  Serial.println(data,HEX);
  *out &= ~bit;

  noInterrupts();
  for (int i = 0; i < LED_COUNT; i++) {
    DORGB(leds[i][0], leds[i][1], leds[i][2]);
  }
  *out &= ~bit;
  Serial.println(uint8_t(*out),BIN);
  interrupts();
}

void setpixel(const int index, const uint8_t r, const uint8_t g, const uint8_t b) {
  leds[index][0] = r;
  leds[index][1] = g;
  leds[index][2] = b;
}
void fill(const uint8_t r, const uint8_t g, const uint8_t b) {
  for (int i = 0; i < LED_COUNT; i++) {
    setpixel(i, r, g, b);
  }
}

void loop() {
  const uint8_t ONE = 0b00111111;
  const uint8_t ZERO = 0b00000000;
  const int DELAY = 2000;

  fill(ONE, ZERO, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ONE, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ZERO, ONE);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ONE, ONE, ONE);
  show(SEWRGB_PIN);
  delay(DELAY);

  fill(ZERO, ZERO, ZERO);
  show(SEWRGB_PIN);
  delay(DELAY);
}

I think the problem is this: volatile uint8_t * out = portOutputRegister (port);

in, fubarino Sd volatile uint32_t * out = portOutputRegister (port);

then it returns one uint32_t, so that the composition is altered byte here:

#define DOBIT(_bit) do {
if ((_bit)) {
*out |= bit;
*out |= bit;
*out |= bit;
*out &= ~bit;
*out &= ~bit;
} else {
*out |= bit;
*out &= ~bit;
*out &= ~bit;
*out &= ~bit;
*out &= ~bit;
}
} while (0);

#define DOBYTE(_byte) do { \
  const uint8_t __byte = (_byte); \
  DOBIT((__byte) & 0b10000000); \
  DOBIT((__byte) & 0b01000000); \
  DOBIT((__byte) & 0b00100000); \
  DOBIT((__byte) & 0b00010000); \
  DOBIT((__byte) & 0b00001000); \
  DOBIT((__byte) & 0b00000100); \
  DOBIT((__byte) & 0b00000010); \
  DOBIT((__byte) & 0b00000001); \
} while (0);
#define DORGB(_r,_g,_b) do { \
  DOBYTE(_g); \
  DOBYTE(_r); \
  DOBYTE(_b); \
} while (0);

how can I fix this?, here's one otecto, 1 byte, should now be 4 bytes?

0b10000000


GrahamM242

Wed, 30 Apr 2014 09:17:30 +0000

Basically, the code in question is looking up the port register so that it can then bypass the Arduino API and operate directly on the port hardware. This is probably because using the Arduino API would break the timing needed for the WS2812.

In any case, the code you have needs significant re-writing, as the timing is directly coupled to the processor speed. The code is written for a 16MHz ATMega, and you're now running it on an 80MHz PIC32MX. Instead of trying to re-write that code, you may find the code at http://myroundpeg.blogspot.co.uk/ easier to work with, as it was written for a ChipKit Uno32 and should work on the Fubarino SD.

I made half an attempt to write my own SPI based WS2812 driver, but there's still issues with it that I haven't been able to work out.


Omnimusha

Wed, 30 Apr 2014 16:09:35 +0000

Basically, the code in question is looking up the port register so that it can then bypass the Arduino API and operate directly on the port hardware. This is probably because using the Arduino API would break the timing needed for the WS2812. In any case, the code you have needs significant re-writing, as the timing is directly coupled to the processor speed. The code is written for a 16MHz ATMega, and you're now running it on an 80MHz PIC32MX. Instead of trying to re-write that code, you may find the code at http://myroundpeg.blogspot.co.uk/ easier to work with, as it was written for a ChipKit Uno32 and should work on the Fubarino SD. I made half an attempt to write my own SPI based WS2812 driver, but there's still issues with it that I haven't been able to work out.

WORKS, THANK YOU FOR YOUR HELP


GrahamM242

Thu, 01 May 2014 11:30:49 +0000

WORKS, THANK YOU FOR YOUR HELP

Great stuff! What's the project are you making?