WS2812B leds combined with serial coms

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good evening!

 

I got to wonder how people do this? the led's have pretty tight timings and interrupts kinda screw it over.

 

i was thinking something like this:

  1. PC sends byte (kinda like message that there is data waiting)
  2. AVR retrieves the byte when it can, ie. after the led driving routine when interrupts get re-enabled.
  3. AVR sends byte which indicates its ready to receive.
  4. Now PC sends the information

 

What i was wondering with this, is that does the UDR register get "flushed" or something when interrupts are re-enabled?

Or does the USART_RX interrupt actually fire after re-enabling interrupts if theres data in UDR?

 

If someone have other ideas, better or worse i'm happy to hear about these, maybe it will bring completely new ideas to implement this in my head.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JoniS wrote:
Or does the USART_RX interrupt actually fire after re-enabling interrupts if theres data in UDR?

What does your AVR's datasheet say in the paragraphs about Interrupt Handling?

 

What does your AVR's datasheet say about the firing of the RXC interrupt with respect to UDR contents?

 

Re your general question:  I seem to recall threads about the "tight timing" LED driving.  The simple questions:

 

1)  How long does it take for a complete sequence of the LED driving?

1a) How often is that repeated?

2)  How does the timing in 1) and 1a) compare to the line time for a USART character frame?  ~1ms at 9600bps.  ~100us at 115200.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
What does your AVR's datasheet say in the paragraphs about Interrupt Handling?

From one AVR datasheet, Mega16A:

There are basically two types of interrupts. The first type is triggered by an event that sets the
Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding
Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s)
to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is
cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is
cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt
Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the
global interrupt enable bit is set, and will then be executed by order of priority.

The second type of interrupts will trigger as long as the interrupt condition is present. These
interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the
interrupt is enabled, the interrupt will not be triggered
 

Now, I'm a veteran AVR8 user.  But I have to think about that "second type of interrupts".  Yes, there are those that are level-triggered.  Which >>do not<< have flags?!?  Let's peek at the Mega16A vector table, and see if we can find any:

Table 11-1. Reset and Interrupt Vectors

Vector No. Program
Address
(2)
Source Interrupt Definition
1 $000(1) RESET External Pin, Power-on Reset, Brown-out Reset,
Watchdog Reset, and JTAG AVR Reset
2 $002 INT0 External Interrupt Request 0
3 $004 INT1 External Interrupt Request 1
4 $006 TIMER2 COMP Timer/Counter2 Compare Match
5 $008 TIMER2 OVF Timer/Counter2 Overflow
6 $00A TIMER1 CAPT Timer/Counter1 Capture Event
7 $00C TIMER1 COMPA Timer/Counter1 Compare Match A
8 $00E TIMER1 COMPB Timer/Counter1 Compare Match B
9 $010 TIMER1 OVF Timer/Counter1 Overflow
10 $012 TIMER0 OVF Timer/Counter0 Overflow
11 $014 SPI, STC Serial Transfer Complete
12 $016 USART, RXC USART, Rx Complete
13 $018 USART, UDRE USART Data Register Empty
14 $01A USART, TXC USART, Tx Complete
15 $01C ADC ADC Conversion Complete
16 $01E EE_RDY EEPROM Ready
17 $020 ANA_COMP Analog Comparator
18 $022 TWI Two-wire Serial Interface
19 $024 INT2 External Interrupt Request 2
20 $026 TIMER0 COMP Timer/Counter0 Compare Match
21 $028 SPM_RDY Store Program Memory Ready

 

I guess that while UDRE is described as a "flag", it could/would fall into that second category -- if it goes away then the corresponding enabled interrupt wouldn't fire.  Hmmm--how could that happen?  I guess code could load UDR when interrupts are disabled.  Then, a set UDRE would clear, and the interrupt would not fire when re-enabled.

 

EE_RDY and SPM_RDY?  I guess those would fit the bill.

 

None of the above directly apply to your query.  And in a quick scan I think all the others have "conventional" 'sticky' interrupt event flags.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
1)  How long does it take for a complete sequence of the LED driving?

 

That will highly depend on how many led's i may drive at once(i actually use assembler driver made by someone else, with my own routines to make effects with the leds), if i haven't completely mistaken its about 30us per led -> 30*80 = 2400us

 

theusch wrote:
1a) How often is that repeated?

 

This will depend on the effect i'm creating with the leds. ie with "breathing" effect it's ~5ms break between the calls to led driving routine, to get smooth fading.

 

theusch wrote:
How does the timing in 1) and 1a) compare to the line time for a USART character frame?  ~1ms at 9600bps.  ~100us at 115200.

 

Basically there is plenty of time to read bytes from usart in between the calls to led driving routine with high baudrate, or another way would be to slow down the baud rate and never miss byte because the transmission speed is so slow.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JoniS wrote:
That will highly depend on how many led's i may drive at once

Well, yeah -- but that is still an [the?] important piece of information w.r.t. your query.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

JoniS wrote:
That will highly depend on how many led's i may drive at once

Well, yeah -- but that is still an [the?] important piece of information w.r.t. your query.

 

 

Yes it is important information, hmmn, in the "worst case scenario" I will have 80 LEDs which makes the driving routine last about 2400us each time, then there will be about 5ms(+setting the led arrays with values) "free time" before new call is made to update the LEDs, I guess the the commucation should be implemented around these values, since this is time when the avr is most busy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the led's have pretty tight timings and interrupts kinda screw it over.

Then use a small, dedicated, chip to drive the LEDs that request the data from the master when ready.

 

In the process of finishing off (at last) a project that has 5m LED strips with 300 LEDs per strip, about 14,000 LEDs altogether. A beaglebone board is used to drive them, the chip used has 2 PRUs that are basic 200MHz processors, these talk to the LEDs and grab the data after sending out the packets.

 

A similar thing can be done with AVRs, one or more small chip with enough RAM to hold the packet and maybe communicate with the master via SPI.

 

But yes, interrupts are a no-no while the packet is being sent.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes 30 us per LED, so yes 2400 us for 80 LEDs, not including 50 us for the frame start reset, so 2450 us.  The USART receiver can buffer 3 bytes (two-byte buffer plus 8-bit shift register), so the shortest sustainable bit period at 8N1 is 2400 / (10 * 3) = 80 us, for a maximum sustainable baud rate of 12,500.  The highest standard baud rate is 9600.

 

Are you updating each one separately?  So that's 80 separate grb triplets, for 240 bytes per update.  At 9600 baud, you can have a maximum of 4 full serial updates per second.

 

the led's have pretty tight timings

They don't actually.  The datasheet is pants.  See this lengthy thread, with interesting details starting in post #68.

 

A carefully (probably in assembler) written system could meet the real (not stated) timing requirements of the LEDs, while still picking off incoming bytes from the USART and stuffing them into a buffer, without losing 'sync' with the LEDs.

 

While the spec states 800 kHz, or 1.25 us per bit, with a maximum of something like 1.5 or 1.8 us, in reality this can be stretched to more than 7 us with no ill effect.  This leaves plenty of CPU cycles to poll RXCn, fetch UDRn, stuff it into a buffer, and increment a pointer.  In fact, after the 0.7 us T1H time period, you can spare another 6.4 us before you must begin the next bit.  At 8 MHz that's 51 CPU cycles.  Plenty.  It can probably be done in less than 20, or 2.5 us.  If so, then with an effective bit time of 3.75 us, the update time per LED rises to 90 us, or 7200 ms for 80 LEDs.  That's still over 130 updates per second, far faster than the eye can see.

 

In practice, you couldn't make use of more than 1 incoming USART byte per 8 LED bits anyway, so the majority of the bits would still be 1.25 us.  Seven out of every eight.  Only one out of every eight would need to be stretched to read an incoming byte.  So an LED update then takes 1.25 * 7 + 3.75 = 12.5 us per byte, 37.5 us per LED, or 3000 + 50 = 3050 us for 80 LEDs, or 320 per second.  With 12.5 us per byte, at 8N1 you could feed it with up to 1000 / 1.25 = 800,000 baud.  In practice, the standard 460,800 baud would still allow you to send up to 192 updates per second.

 

I have a back-burnered plan to implement a similar system, but it's not a priority because I haven't needed that kind of performance.  A current system I have updates 140 LEDs in 20 banks of 7 from a DMX lighting console, using 60 DMX addresses.  DMX frames arrive at a rate of about 38 per second (26000 us per frame).  At 250 kbps 8N2, the 60 DMX addresses take 2640 ms to receive.  The 140 LEDs take 4200 us to update, leaving almost 20000 us of free time between each received frame.  Worst case is if my device is addressed at the upper end of the DMX address space (universe), it might miss the start-of-frame break on the next frame while it is updating the LEDs, so my update rate drops to half of the DMX frame rate, or about 19 per second instead of 38.  No biggie.   So there was no need immediate need to develop a more sophisticated system.  But like I say, it's on the back burner.

 

What is your objective?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Aug 23, 2017 - 03:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Gotta love the WS2812B LED's!

 

JS mentioned a multi-chip implementation already.

 

A slight spin off would be to use one uC and a FTDI USB to USART bridge chip as the second chip, especially as you mentioned PC comm's.

 

Let the FTDI chip buffer the incoming data (requests) from the PC.

 

Set a micro up for an interrupt every X mSec, (CTC mode).

 

On alternating interrupts either output a new data packet to the LED string, or read in and/or process a command from the FTDI buffer, which came from the PC.

 

BTW, my first driver for them was an over-clocked Xmega.

As I wasn't using any analog or EEPROM functions, I clocked the Xmega at 48 MHz, at which speed I could write my driver in Basic, (not Asm).

It worked great.

 

Since then there is now a WS2812B library so any Tiny/Mega/Xmega at 8 MHz clock or higher can drive them, interfaced from the High Level Lang.

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
Gotta love the WS2812B LED's!

Yes! 

 

Ps. I need to read this all again after work when I have woke up fully, will try to answer questions then.

 

Edit: what I think I wasn't too clear about in the initial post, there is no need for "live data" at the given moment which would be directly fed to the LEDs all the time(thougth it would open a sweet idea to use audio stream as input), but rather chunks of information about colors(primary, secondary...), Brightness (min/max/static) and stuff like that whenever i feel I want something different, which the avr then uses to calculate the effects like "breathing" or "running led(s) with tail(s)" and such, so the data transfer and applying it to LEDs does not have to be 100% instant, but delay should be small as possible of course to not get "laggy" feeling when changing color for example.

 

Anyway to sum up the ideas of the coms implementation for myself.

2x MCU,

ftdi uart bridge(with handshaking?),

Isr to control leds/read usart(is this one of the cases where long isr is not so big NO after all?).

 

Last Edited: Wed. Aug 23, 2017 - 04:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

faster mcu.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

faster mcu.

This can definitely be done with an 8 MHz AVR.  I've taken a quick look and (although I've not fully tested or even written it) can add concurrent USART RX in the 8th bit of every LED byte at a cost of no more than 14 cycles.  That leaves the bit time for the 8th bit to 2.5 us instead of 1.25 us, still well within the 7.125 us limit pointed to by my tests detailed in the above-linked post.

 

No need for hardware handshaking FTDI.  No need for a second MCU.  No need even for interrupts, although they can be used if desired.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]