CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

controlling a neopixel with spi
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
doguhanpala



Joined: 05 Oct 2016
Posts: 94

View user's profile Send private message

controlling a neopixel with spi
PostPosted: Wed Feb 08, 2017 6:28 am     Reply with quote

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
diode_blade



Joined: 18 Aug 2014
Posts: 23
Location: Sheffield, South Yorkshire

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 08, 2017 6:45 am     Reply with quote

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.
temtronic



Joined: 01 Jul 2010
Posts: 6249
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 6:48 am     Reply with quote

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
doguhanpala



Joined: 05 Oct 2016
Posts: 94

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 6:49 am     Reply with quote

thank you very much!
doguhanpala



Joined: 05 Oct 2016
Posts: 94

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 6:55 am     Reply with quote

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.
Ttelmah



Joined: 11 Mar 2010
Posts: 13526

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 7:21 am     Reply with quote

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.
doguhanpala



Joined: 05 Oct 2016
Posts: 94

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 8:12 am     Reply with quote

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
Ttelmah



Joined: 11 Mar 2010
Posts: 13526

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 8:44 am     Reply with quote

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
temtronic



Joined: 01 Jul 2010
Posts: 6249
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 8:50 am     Reply with quote

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
Ttelmah



Joined: 11 Mar 2010
Posts: 13526

View user's profile Send private message

PostPosted: Wed Feb 08, 2017 9:05 am     Reply with quote

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.
Kroko87



Joined: 20 Jan 2011
Posts: 4

View user's profile Send private message

PostPosted: Thu Feb 09, 2017 1:08 am     Reply with quote

If you want to control those RGB LEDs with SPI, then you have to use a PIC with integrated CLC.

Look here: http://geek-mag.com/posts/255612/
AppNote: http://ww1.microchip.com/downloads/cn/AppNotes/00001606a_cn.pdf
doguhanpala



Joined: 05 Oct 2016
Posts: 94

View user's profile Send private message

PostPosted: Thu Feb 09, 2017 1:50 am     Reply with quote

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
Ttelmah



Joined: 11 Mar 2010
Posts: 13526

View user's profile Send private message

PostPosted: Thu Feb 09, 2017 8:44 am     Reply with quote

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.
temtronic



Joined: 01 Jul 2010
Posts: 6249
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Feb 09, 2017 9:39 am     Reply with quote

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
Woody



Joined: 11 Sep 2003
Posts: 23
Location: Warmenhuizen - NL

View user's profile Send private message

PostPosted: Thu Feb 08, 2018 1:55 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group