Controlling WS2812 LEDs

I thought this might come in use for people wanting to simply control a strip of WS2811/2812/2812B LEDS. This is not all-singing – you can control individual LEDS but the fancy stuff you’ll find elsewhere.  In my case I wanted to smoothly update a whole array of these things in a home control board using the minimum of room and having to do the least setup or re-programming.

I’ve been using the ADAFRUIT library for some time – that is all singing – but.. it also has bugs. I found when adjusting colour and brilliance of strips of LEDS at the same time there were inconsistencies – also the library was using up a lot of space I could not afford. So I went off looking.

I stumbled across THIS library.

https://github.com/cpldcpu/light_ws2812

You’ll find if your needs are simple this does a lot of what you want – basically you define an array of LEDS – set the colour for each one – or the lot in a loop – and call the update routine – no setup for different types – it just WORKS and works quickly and takes up very little room.

But it was a TAD too basic. So I added some stuff. I wanted to be able to dynamically adjust the number of LEDS without reprogramming the chip. On inspection the room for each led (3 bytes per LED in RAM)  is MALLOCed… so a simple addition to the library…

Add this to the public definitions in the header

image

and some code into the main SW2812.cpp file..

tmp7B7F

And that’s it – so now you can change clear an array of LEDS to off – OR specify an RGB colour for the lot.

All of that was fine – all I needed now was a routine that could be called in the background…..

I have a byte variable which contains the brilliance of the strip – and another which contains a colour from a FLASH-based lookup table…

For historical reasons these bytes are called neocol and neobright.

Here’s the lookup table – you don’t need it of course but I was short of room.

tmpD7A4

 

And here is a routine you might call – every few milliseconds – to arrange smooth change of colour and brilliance to your array as you set those two values…

tmp1C33

I hope that proves useful to you – compared to similar code using Adafruit I gained over 1k of code space back and it does a smoother job.

Advertisements

Blowing Bootloaders into Atmel Chips

A couple of Atmel Chips – the 1284p and the Attiny85 came my way recently – well I say a couple, a few of each – and for the first time I found myself having to program bootloaders for them.

To explain – hobbyists buying the likes of Arduino microcontroller boards generally just have to program “sketches” or programs onto them – and that’s often done with a little serial converter plugged into the USB of their computers. But if you get free samples or come across raw chips not intented for Arduino, they are utterly blank. That is, they don’t have a bootloader – or the minimal code necessary to let you use the serial interface etc.

There are a couple of links here which I’ve used and which work.

http://www.kobakant.at/DIY/?p=3742

The above link lets you program an aTTINY or similar device using an Arduino board (or clone) as a programmer. The Arduino IDE comes complete with a sketch for this – basically blow the sketch onto your Arduino, put a capacitor between reset and ground on the Arduino (to stop it resetting) and then use that Arduino to blow the bootloader onto the Attiny… it’s all in the link – just don’t forget the cap and check your wiring carefully – blowing the bootloader takes seconds. You can then (again without removing the cap) blow sketches onto the little chip – for a test I used the BLINK sketch but changed the output pin to “3” which actually makes physical pin 2 on the chip flash.

The 1284p on the other hand is a different monster – this 40 pin chip has the most RAM of any of the chips while retaining DIP packaging which is ideal for messing around with.  Here’s the link:

http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/

Similar setup though I don’t recall anything about a capacitor in this case.  One thing you might have issues with the 1284p – is blowing sketches with your serial interface…. if that’s not reliable, I read somewhere that some of the chips have a design issue and that the RX in should have a 10k series resistor – with a 0.1u cap from the RX pin to ground – well, I DID have issues, programming sketches would often stop after a few seconds and that DID fix it for me – I’m happily blowing large sketches into these chips now.

Home Control Update

1284p main board with LCD panel up front

Just a quick update on the home control… the slaves are about as good as they can get – I’ve added memory for the state of the 3 PWM outputs and ALLOFF and ALLON commands so that one can set the brilliance of, say a 3-colour LED strip – and then turn the lights on and off accordingly. At some point I’ll put a global fader on all 3 colours….

I’ve switched my attention now to the master board. I was using a MEGA, having long since given up on the 328 due to constantly running out of memory. I had a few 1284p chips lying around – in case you don’t know these are the largest Arduino-type chips you can get in DIP format – 40 pins – and they have one great feature – 16K of RAM which means you can forget about penny-pinching RAM.  Accordingly – I’ve added SD logging – and just now for the sake of it, an LCD display. I’m using the new LCD library that lets you use an LCD module with a 74HC595 shift register on the back (on veroboard) to reduce the pins needed to talk to the processor down to 2 (clock and data). 

As you can see above, the LCD is echoing the Ethernet commands as they come in (and quickly too) and over on the left is the micro-SD card plugged into the Ethernet card…. which is also supplying the 3v3 to the radio board. All in all very few components – took me an hour or so to put this lot together and twice as long to remember how to use the various libraries.

All working well, not sure if there’s a REAL use for the LCD – I also have a 4-line version of that… overall current for the board is around 300ma – or 1.3 watts – that won’t break the bank running all the time and it should run off a standard USB plug-in-the-wall.

The next challenge is a box.  I have to say, it’s all working very well – once again for pinouts etc I keep referring back to ManicBug’s various articles.

Arduino Home Control Part 1

Background
A little background before I launch into a project I’m working on..

In the closing decades of the last century, just as the Internet age was about to start, I was one of two directors in a small company who innovated in electronics – we did it in a variety of ways, some projects were successful, some before their time and just occasionally came the odd project that was not completely thought out.

Home Control last-century style
Home control fell into the latter category. We were into using the PIC chips (from Microchip) at the time and we ended up with a bee in our bonnet about home control – wouldn’t it be nice to have little boards all over the house controlling stuff.  We developed the product before too deeply considering the market – but what a product it was for a time.

Essentially a small board with a PIC, a TRIAC output (for controlling lights and heaters – and yes we could handle compact florescent lamps without issue thanks to a VDR), a digital temperature sensor (Dallas), a couple of inputs and a simply transistor switch to control PWM sound output. The board was smaller than a pack of cigarettes, cheap, ran on 12v and had a unique ID number.  We could connect maybe 128 of these along a 4-core telephone wire (normal white twisted pair stuff commonly in use today).  We could manage maybe 100 metres.  At the end we had a little board which provided 12v power and interfaced by RS232 with a PC. A program on the PC showed a plan of the house and the boards showed as little coloured block superimposed on the map of the house. The colours changed depending on the input and output status of the boards in real time – and you could write a set of rules to control what the boards did. The 4th wire ran simple PWM sound from the PC speaker around and a transistor could be programmed on any board to turn on – hence enabling sound routing to any board.

Application Control
We called the system “Appcon” which immediately got us into trouble with someone in the apparel industry and we had to promise not sell competing products!! To give you an idea of how incredibly powerful this system was, in my home which had 40+ of these units, I had wall-mounted PIR movement sensors hooked to inputs, heating, lighting and alarm hooked to outputs as well as door magnetic sensors.

I could route cricket or bird sounds to speakers in the garden, I could detect open doors and turn the heating up depending on the time of year, with a closed switch I could enable an alarm system (all done by rules using nothing more than the basic devices and inputs – and my PC) and of course enable PIR triggered yard lighting only during certain hours of the day.

The Automated Home
A magical system and make no mistake, it  was successful in a small-business kind of way, we sold many hundreds of the units, we got in major PC magazines – for example PC-Answers May 1984 – “Wired Tales” heavily featured the system as did many others. We got the hobbyist market and that was it and really there was no way to make a fortune out of this – but we had great fun developing it, making new friends who were equally fanatical about home control – but then the problem was wires…

As I’ve found out in my cottage here in the country – with solid floors and 18-inch thick walls – you just can’t go putting wires all over the place – partners get really fidgety about this stuff.. but then the alternative, inexpensive radio doesn’t work too well through solid walls either and over-the mains control – well that tends to be limiting and expensive.

There are solutions out there today, lots of them, but they have severe limits and are relatively expensive. Somehow the idea of paying £20 to £30 for a board to control a light seems ludicrous to me and the cheaper systems are inflexible to say the least.

Moving ahead 28 years…

I’m into Arduino right now – which is merely a modern-day PIC (well, the PICs are still around and surprisingly little has changed there) and for some time I’ve been thinking of home control – the problem is that wiring just won’t work for me here… and radio modules generally are just too expensive to incorporate into boards – well, unless you want to throw away £30-40 all in just to control a lamp!!

Cheap Radio Solution
I recently discovered the NRF24L01 boards, available from China on Ebay for less than £2 (now THAT’s more like it) and if you’re into Arduino you’ll know that given the chip (the most expensive part and some suppliers really rip people off) you can put together a board for WELL under a tenner.

Line of Sight Radio
Ok, that’s a start, I looked up libraries to handle the radio chip and one, RF24, does a cracking job of one-to-one communication. Sending a small package of data from one device to another reliably is easy with these boards and the library. But we need to be realistic – the range is limited.

My pal and I did some tests a while ago – out in the open – MAYBE 60 metres on a nice day.. we tried the really cheap units and the ones costing 3 times as much with a nice stubby aerial – not that much difference amazingly so we stuck with the cheap units.  What does make a difference is speed – you can run them at up to 2Mbps – but drop that down to 256Kbps – and your range goes up to maybe 80 metres line of sight.

That’s open air – what about indoors? – OH DEAR ME… thick stone walls just about cripple the signal  – in my cottage I can just about manage to get through an 18” thick stone wall, you’re talking 20ft IF YOU ARE LUCKY. In other homes with thin internal walls  I’ve seen 40ft or more. It all depends on wall thickness and materials, on what other radio devices are operating etc. I was about to give up – but then started to think about networking – what if you could bounce the signal around as in networks – cellnet, Internet etc.. I thought I was asking too much of a small, cheap radio but the chips do have the basics of networking in them – they can LISTEN to up to 6 channels at once (but can’t listen AND send at the same time)  – maybe there was a future in this?

Networked NRF24L01?
I scoured the web, lots of half-arsed projects that went no-where and ONE project that looked like a starting point – it’s called RF24NETWORK.  It’s not a true network in so far as plugging in arbitrary units and having them relay stuff all over the place – but it’s a start and enough to make a practical system albeit for those who didn’t utterly fail maths.

I started playing with the library and with examples and had some teething problems – some of the examples would not work on the latest Arduino development environment (IDE) and some of the stuff was not too clear. I wrote to the developer. Nothing. I went to his website and wrote there – nothing. He’s either on holiday, or busy or dead – either way it looks like for now the one and only simple network is unsupported – but the good thing is – it works (there’s a caveat later). I wrote an article on the NRF24L01 and the RF24 library here originally.

Limited Network
I need to clarify… the NRF24L01 chips can listen to 5 other devices at once… that’s it. So how do you make use of that? The way RF24NETWORK code does this is to ask you to regularly call a function on all of your boards – this function transparently handles the networking. You have to number your boards. The boards are numbered in Octal (don’t let that put you off – the designer has used this to make best use of the 5-byte addressing) and Octal in Arduino is expressed with a leading 0. So, to express the Octal “222” you simply preface it with a zero – 0222.

This incredibly easy online convertor makes it all clear. 0222 is 146 in decimal for example. This is irrelevant of course but as this caught me out at first I thought I’d better explain why I’m prefacing numbers with zeros!!

There are numbers, then there are numbers
So, given that the boards can talk to 5 others – it makes sense to build a tree structure – any device can talk to a device further up the tree – and 5 devices below it. Device 1,2,3,4,5 can all talk to device zero (0) – and 0 can talk back to them – directly.  Moving outwards from there involves some hopping – BUT FEAR NOT as the software does that for you automatically – you just have to think about your numbering. In theory such a simple network should be easy to build but I can’t get my head around the acknowledge signals travelling up and down (how can you have unique packet numbering to ensure packets get there – when you can’t talk directly to the root!)… so for now, RF24NETWORK gets the job until someone comes up with a better solution.

It’s getting too complicated
The numbering system is well described in the RF24NETWORK pages so we’ll not go into that here. Suffice it to say you can attach thousands of units together – but I was thinking more of 2-100! I’m sitting here with device 0 talking to device 02 which is acting as a gateway to device 022.

Relax – you don’t need to know any more
So we’re talking hundreds of potential devices. Now it’s important to realise you just need to understand the numbers – nothing else as the networking software handles the rest.

If course all of this is ok but as units can’t talk and listen at the same time – I figured a controller was needed… and then what – you need to DO something with all of this… and I started a series of brainwaves which brings us to where I am now – developing a working home control system based on nothing more than cheap Arduino-type boards.

And that is the end of part 1 – in part 2 we’ll look at putting some meat on the bones – and yes, I’m sitting in front of a basic working system here, this isn’t going to be merely an academic effort – but there are some issues – read on.

See part 2.

Arduino Timer– To Overflow or not to Overflow

Part of the learning curve in mastering the use of the Arduino – is how to use delays. The simplest sketches (programs to most people) show turning a light on, waiting a second, turning it off, waiting a second… in a permanent loop.

Still don’t know what an Arduino is? Well, perhaps you should because Google want to put these things in our schools – it’s like a PIC chip but different – a cheap and cheerful way for kids to learn about computers… or put another way, a damned powerful and CHEAP microprocessor to let you do control experiments – timers, lighting systems, heating control, robots….. you name it.

That’s easy – but almost NO programs are so simple that all they do is flash lights (though the chip does a cracking job of emulating a police car set of lights given red and blue LEDS)! The problem with delays is that you can’t DO anything while waiting for the delay to finish.

Perhaps you might want to get clever and make use of interrupts to ensure that certain things happen at the right time – the problem with that is one of volatility – i.e. using variables in the interrupt routine (which can happen at any time) which may be affected by stuff going on in the main program – and vice-versa. Yes interrupts are do-able but anyone who tells beginners that interrupts are easy is delusional. If there’s another way, simple avoid the subject.

I figured instead I’d make use of a standard Arduino routine called millis() – quite safe, it tells you how many milliseconds have elapsed since the chip was last reset. Well, that’s easy – except that it isn’t. There is a whole lot of mumbo-jumbo about how long it takes before millis() overflows… and what does that mean?

It is quite simple really, the millis() routine stores it’s value in an "unsigned long" which you can’t easily access – no black magic, this is a 32-bit number which can count from 0 to just over 4 billion – and that doesn’t take too long really at a count of 1000 a second. Depending what you are building that might not be a problem but any program with any kind of long term timer might end up in trouble.

So as an alternative to sitting in a loop you can look to see how long it was since the last time you read millis() and run code accordingly. The problems with that are two-fold… eventually millis() will reset and you could end up with a duff comparison – OR you could be busy doing something else, call millis() a little late… and now the WHOLE thing is put back a little. Accumulatively you end up building up inaccuracies over time that could be significant.

I decided I needed a delay that was accurate and if I was a little late calling it – well, it would time a little earlier next time to make up for lost time – then I realised people might not want this – even if they were way too late they might not want another call before the minimum specified… so I looked around for routines to do the timing and offer the option of catching up or not. Look for METRO library – sounds great but in order to retain accuracy you have to call that at least every millisecond – WHAT? The simplest DALLAS temperature chip calls sometimes go away for a SECOND… I’ve fixed that incidentally – but you know what I mean.

So, I needed a routine that would handle overflow, that would not mind my calling it a bit late and would give me options to compensate next time for the delay – or NOT.

I’ve wrapped this in a class just really to make sure I understood classes.. and put it on GITHUB again just as a training exercise.

Enjoy.. but TEST – don’t take my word that this works…. if you want to test the overflow- remember the limit for a 32 bit number in HEX is FFFFFFFF (ie 6 Fs). Consider a last timing just under that- add the interval – you get a lower value as it overflows – but actually do the math and you’ll find the difference is still a positive number because both millis() and the comparison are 32 bits and so it still works.

So now you can write a program with routines that might take some time – and you can then check for intervals… an example might be to update the screen every 1 second – if you’re not fussed about accuracy use TRUE for the last parameter – on the other hand you might want a rock-steady beep every second – use FALSE or 0 as the last parameter.

As always a thanks to my pal Aidan – in this case the answer was mine but simply the ability to have someone to bounce the questions off and get intelligent answers makes all the difference.

Incidentally this is NOT super-accurate – you may check the routine at any time – not just dead on the millisecond so WORSE CASE you might find a stagger of somewhat less than a millisecond – ok 1 in a 1000 isn’t that bad – but it’s not perfect. It might mean in a real time clock the difference between catching a show and missing the first second or so Smile

So simple – but it does work. Proof…. call every 1000ms and print out the value of millis() on an LCD and it will display having added 1000 every time i.e. it remains accurate.

class Timing
{
private:
 unsigned long counter;
 boolean catchup;
 
public:
    void begin(boolean cat)
    {
        counter=millis();
        catchup=cat;
    }
        
    boolean isOver(unsigned long interval)
    {
        unsigned long newmillis=millis();  // temp vars so easier comparison
        if ((newmillis-counter)>=interval)
            {
            if (catchup) counter=newmillis; else counter+=interval;
            return true;
            }
        return false;
    }
};

// you can hide that class in an include file... so here's how to use it.
Timing myTimer;

void setup()
{
 myTimer.begin(0); 
 // 0 means catch up, 1 means delay will always 
 // be at least the value stated
}

void loop()
{
   if (myTimer.isOver(1000))
     {
        // do something here
     }
}

This code may be improved on – and I’m most likely to store improvements over at GITHUB. Here’s the link for the latest version. Enjoy.

Peter Scargill