View previous topic :: View next topic |
Author |
Message |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
controlling a neopixel with spi |
Posted: Wed Feb 08, 2017 6:28 am |
|
|
hello everyone
I am trying to control a WS2812 RGB led with 18f2550. I read the datasheet and it says i should send 24 bit data for a color. First 8 bit is for green, the next 8 bit is for red and last 8 bit is for blue. As far as i understood, the value of this 8 bits are the duty cycle to set brightness. The datasheet says i should wait 50 us before i send next 24 bits.
In case of i misunderstood what the datasheet said there it is:
https://cdn-shop.adafruit.com/datasheets/WS2812.pdf
The problem is i can't see the color i want. I wrote the code below.
Code: |
#include <18F2550.h>
#fuses INTRC_IO, NOWDT, PUT,NOMCLR,NOPROTECT,NOLVP,NODEBUG,NOBROWNOUT,CPUDIV1,VREGEN
#device ADC=10
#use delay(clock=4000000)
//#use rs232(baud=9600,xmit=PIN_B0,rcv=PIN_B1)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_H_TO_L)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
void main(void)
{
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_16);
while(true)
{
spi_write(0x00); //green
spi_write(0x00); //red
spi_write(0xFF); //blue
delay_us(50);
}
} |
I expected to see just blue but no luck. I changed the numbers inside spi_write() function, tried integer, binary and hexadecimal. There was no difference. I tried removing the while loop and sent these values just one time. Since it changed nothing, i think i am not succesfully sending anything. Is the problem with the clock, or fuses? Can anyone point me to my mistake? Thank you very much!
Best wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
diode_blade
Joined: 18 Aug 2014 Posts: 53 Location: Sheffield, South Yorkshire
|
|
Posted: Wed Feb 08, 2017 6:45 am |
|
|
Hi doguhan,
I wrote some code for controlling WS2812 60 pixel led string unit using another compiler, I think I also wrote a CCS C version, I will check when I get home from work and let you know. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Wed Feb 08, 2017 6:48 am |
|
|
From memory... the 2812 is NOT an 'SPI' compatible device but the 2801 is. I had the same problem 3-4 years ago and 'somewhere' on the net IS a 2812 driver. Have a look at the data sheet again...has to be a drawing ,well I think there is .
I recall the 2812 has different pulse widths for '1's and '0's unlike SPI where their widths are the same.
Use Google 'ws2812 driver ccs c' and it should find something for you.
I'm doing this from the NET PC not the ENG PC( no outside access )
Jay |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Wed Feb 08, 2017 6:49 am |
|
|
thank you very much! |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Wed Feb 08, 2017 6:55 am |
|
|
temtronic wrote: | From memory... the 2812 is NOT an 'SPI' compatible device but the 2801 is. I had the same problem 3-4 years ago and 'somewhere' on the net IS a 2812 driver. Have a look at the data sheet again...has to be a drawing ,well I think there is .
I recall the 2812 has different pulse widths for '1's and '0's unlike SPI where their widths are the same.
Use Google 'ws2812 driver ccs c' and it should find something for you.
I'm doing this from the NET PC not the ENG PC( no outside access )
Jay |
Hello Jay
I don't have any knowlegde about spi. I started searching for it today, since i thought i need it. I saw this code in here.
https://www.ccsinfo.com/forum/viewtopic.php?t=53099&highlight=neopixel
I saw the spi_write function so i thought i should use it. I will check for the driver and search what you said to me. Do you think serial communication would be suitable for what i need?
Thank you so much for your help. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19372
|
|
Posted: Wed Feb 08, 2017 7:21 am |
|
|
I've driven a similar chip from the same manufacturer a while ago.
The interface is not SPI, but can be 'cheated' using SPI. What I did, was clock the SPI from 3.2MHz from T2/2 (I was using a much faster clock than the poster). Then you send the bit pattern '1000' to send a '0', and '1100' to send a '1'. I #defined four patterns, to give 00,01,10 & 11, and then sent these out the SPI.
The chip requires each bit to be about 1.25uSec long (you are not going to achieve this from a 4Mhz master clock), with the '1' having an on pulse that is about 1/2 the bit time, and the '0' and on pulse about 1/3rd the bit time.
It can also be done with the USART, setting this up to give 3.2Mb/sec. However again a much faster master clock is needed. |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Wed Feb 08, 2017 8:12 am |
|
|
Hello Ttelmah
First of all thank you so much for the advise on using crystal, i would spend much more hours on it otherwise.
I have a few questions.
I got confused about the '1000' part. As you and the datasheet mentioned the 0 is 0,35us high and 0,80 us low, 1 is 0,70us high and 0.60 low. You said you defined 4 patterns for 00,01,10,11. I would define 2 patterns for '1' and for '0'. Since you did not do it, i am sure it doesn't work but i did not understand why.
Another question, do i need a timer to set these time values (0,35 us for example)
or is spi's timing enough to do it?
Thank you so much for your help!
Best wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19372
|
|
Posted: Wed Feb 08, 2017 8:44 am |
|
|
The point is you send a byte, to generate each pair of bits of the output. Four bits for each bit you actually want to send. So (for instance), to send '01' (two bits), you have to send the byte 0b10001100.
So I split the byte up into bit 'doublets', and then select these from the #defines, and send the corresponding byte.
You have to program Timer2, to give 6.4Mhz & setup the SPI to use T2/2.
Then to send the byte 0xFF, you send the bytes: 0b11001100 0b11001100 0b11001100 0b11001100
These then give 625nsec on, and 625nSec off for each '1' bit, and 312nSec on and 937nSec off for each '0' bit. This gives 1.25uSec per bit.
You have to be sending the bytes 'flat out'. Nothing else interrupting the code.
The 0.8uSec, is +/- 150nSec, so the 937nSec is OK. Similarly the 0.3uSec is +/-150nSec, so again the 312nSec is OK. The 0.7uSec has the same margin, so again 625nSec is OK.
Last edited by Ttelmah on Wed Feb 08, 2017 9:03 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Wed Feb 08, 2017 8:50 am |
|
|
That code ONLY works for the WS2812B version NOT the WS2812.
According to the datasheets the on-off timings for '1's and '0's is different ! So it is important to read the specs.
While you can 'fudge' or 'bodge' or 'tweak' the SPI data stream, it would be best to start with the datasheet and create a proper bit banged driver. Once you get the basic timing correct, the rest is easy.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19372
|
|
Posted: Wed Feb 08, 2017 9:05 am |
|
|
The figures I give are for the 2812.
Just checked and the timings will also work for the B. The B allows the high for a '0' to be slightly longer. |
|
![](templates/subSilver/images/spacer.gif) |
Kroko87
Joined: 20 Jan 2011 Posts: 4
|
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Feb 09, 2017 1:50 am |
|
|
First of all, thank you all.
Ttelmah wrote: |
You have to be sending the bytes 'flat out'. Nothing else interrupting the code.
|
My project needs to make a color animation, motor drive, read sensors at same time, so this module might not be the best option for me.
Thank all of you so much.
Best wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19372
|
|
Posted: Thu Feb 09, 2017 8:44 am |
|
|
You may well though just be able to send one pattern, re-enable the interrupts, do your other work, and then send the next. Transmitting a whole sequence of 6 bytes takes just 7.5uSec. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9174 Location: Greensville,Ontario
|
|
Posted: Thu Feb 09, 2017 9:39 am |
|
|
I'd start with a 'heartbeat' timer of say 50Hz ( 20ms).
At this rate the LED will appear to be solidly ON,same as Mains frequency.
So the PIC will generate an interrupt every 20ms(20,000us)
Set a 'flag' then exit the ISR.
The LED code only needs 7.5 us
In main(), code a state machine such as
do...
...
if 'flag' is true...then send LED data,clear flag.
...
...do other tests,say for switches and motor controls
...
...forever
Jay |
|
![](templates/subSilver/images/spacer.gif) |
Woody
Joined: 11 Sep 2003 Posts: 76 Location: Warmenhuizen - NL
|
|
Posted: Thu Feb 08, 2018 1:55 pm |
|
|
Must be the time of the year to toy with WS2812b leds, going on the original date of this thread :-)
Anyway, I am using a 16F18326 to control a 4 meter / 240 string of aforementioned LEDS. I managed to make a bit-banged driver that works pretty good; a runner does 1.8 m/s for those 240 LEDS. Bit banging leaves little time for anything else so I searched for an alternative and stumbled on this thread in which I read the brilliant idea of using the SPI to generate the data. After some toying I also got that to work, but this turned out to be a lot slower (0.6 m/s) than the bit-banged version.
This might well be due to me not getting the setup of clock/timer2/SPI correct:
The 18326 runs on its internal clock @32 MHz.
Timer 2: setup_timer_2(T2_DIV_BY_1, 0x01, 1)
SPI: setup_spi(SPI_MASTER|SPI_CLK_T2)
These settings give me a SPI clock with a 500 ns period, or 2 MHz. This makes for 0's and 1's that are slightly longer than need be, albeit just within specs. Entire bytes take much longer than needed. This is not a problem for the ws2812b as long as I do not go over the 50us reset between bits or bytes. But it leads to longer than necessary transfer times and slower operation.
What I do not completely understand is how Ttelmah got T2 to give 6.4 MHz. Was the clock speed much higher? (>51 MHz? Is there a way to increase the SPI clock here? Did I make a mistake in setting the timer/SPI?
I hope someone can shed some light on this.
Paul |
|
![](templates/subSilver/images/spacer.gif) |
|