Driving me NUTS

This has been driving me mad and I’ve only just found the answer – thanks to some clues people have given me – but as many of the responses were wrong – you might well find this interesting.

I have a an array of 180 bytes – for 60 serial LEDs – 3 bytes each for red, green and blue respectively.

So this routine calls back every second – and updates the 60 LEDs which are in a circle. The hour indicator is formed of 7 LEDs, bright in the centre, dimmer to the edges, the minutes indicator is 3 LEDs – again bright in the middle. The seconds are shown as 1 LED.

And it was working a treat – except at midnight where it bombed with all LEDs on – and for the LIFE of me I could not see why..

Ignore the bits in RED….

LOCAL void ICACHE_FLASH_ATTR clock_cb(void *arg)
{
if (sysCfg.clock!=255) // fancy clock on a port
    {
        wsBitMask = (uint8_t) sysCfg.clock;

        int hour12=(tm.Hour%12)*5;
        for (int a=0;a<180;a+=3)
            {
                rgb.buffer[a]=0;
                rgb.buffer[a+1]=0;
                rgb.buffer[a+2]=0;
            }
        rgb.buffer[(tm.Second*3+2)%180]=255; // seconds hand blue

        rgb.buffer[(tm.Minute*3-3)%180]=8; // minutes green
        rgb.buffer[(tm.Minute*3)%180]=255; // minutes green
        rgb.buffer[(tm.Minute*3+3)%180]=8; // minutes green

        int x=((hour12)+(tm.Minute/12))*3;

        rgb.buffer[(x-8)%180]=5;
        rgb.buffer[(x-5)%180]=16;
        rgb.buffer[(x-2)%180]=80;
        rgb.buffer[(x+1)%180]=255;
        rgb.buffer[(x+4)%180]=80;
        rgb.buffer[(x+7)%180]=16;
        rgb.buffer[(x+10)%180]=5;

        WS2812OutBuffer(rgb.buffer, 180,1); // 60 LEDs
    }
}

So here’s the thing – all these years I’ve been thinking % was a MOD operator – it’s NOT – it’s a simple remainder..

In order words..

(-3 % 180) which I had COMPLETELY expected to be returning 177 – was in fact returning –3  !!!!!

That explains a LOT. The solution – a simple MOD function.

LOCAL int ICACHE_FLASH_ATTR mod(int a, int b)
{
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}

Hence mod(-3,180) returns the right answer. Here’s the final clock once-a-second callback routine for a 60-LED array.

LOCAL void ICACHE_FLASH_ATTR clock_cb(void *arg)
{
if (sysCfg.clock!=255) // fancy clock on a port
    {
        wsBitMask = (uint8_t) sysCfg.clock;
        int hour12=(tm.Hour%12)*5;

        int a;
        for (a=0;a<178;a+=3)
            {
                rgb.buffer[a]=0;
                rgb.buffer[a+1]=0;
                rgb.buffer[a+2]=0;
            }

        rgb.buffer[mod(tm.Second*3+2,180)]=255; // seconds hand blue
        rgb.buffer[mod(tm.Minute*3-3,180)]=8; // minutes green
        rgb.buffer[mod(tm.Minute*3,180)]=255; // minutes green
        rgb.buffer[mod(tm.Minute*3+3,180)]=8; // minutes green

        int x=((hour12)+(tm.Minute/12))*3;

        rgb.buffer[mod(x-8,180)]=5;
        rgb.buffer[mod(x-5,180)]=16;
        rgb.buffer[mod(x-2,180)]=80;
        rgb.buffer[mod(x+1,180)]=255;
        rgb.buffer[mod(x+4,180)]=80;
        rgb.buffer[mod(x+7,180)]=16;
        rgb.buffer[mod(x+10,180)]=5;

        WS2812OutBuffer(rgb.buffer, 180,1); // 60 LEDs
    }
}

Facebooktwitterpinterestlinkedin

13 thoughts on “Driving me NUTS

  1. Good thing this bug is solved!
    Maybe you could share a view on this clock of yours?

    1. So the clock came from a YouTube video – a Kickstarter company I think. They’d arranged 60 outward facing LEDS on a circle – so that placed against a wall they would light up the wall. In front of that a slightly larger black perspex ring so you could not see the LEDs – I simply can’t replicate the ring without an engineering company.. so I spotted this ad. Now – I HIGHLY recommend this chap as he sent me off the LED ring (4 segments) and the shipping company screwed up. He tried his best but eventually it turned up too late for what I had in mind. He offered me some bits and pieces as compensation – and when they turned up – he put in a spare ring – he didn’t have to – and I thought that was really nice.

      http://www.ebay.co.uk/itm/Ring-Wall-Clock-60-Ultra-Bright-WS2812-5050-RGB-LED-Lamp-Panel-for-Arduino/271957246415?_trksid=p2047675.c100011.m1850&_trkparms=aid%3D222007%26algo%3DSIC.MBE%26ao%3D1%26asc%3D20140107083358%26meid%3D76da85b758e246d2a68d1c74e9d35f89%26pid%3D100011%26rk%3D1%26rkt%3D10%26sd%3D271930411541

      So from the link you’ll see what the LED ring looks like – WS2812 serial LEDs. So you need 3 wires in total to run it. At first I wrote the software to have one LED for hours, one for minutes, one for seconds. Nice but boring. I then experimented with sub-second displays – 50 updates a second – with all sorts of flashing effects. Not only did that push the ESP a little – but ultimately it was pointless.

      So I ended up with 7 LEDS for the hour (red), brilliance-diminished towards the edges, 3 LEDs for minutes (green) and one for seconds (blue). And that’s when I discovered that the C % operator was not what I thought it was. That fixed I now have added this to my home control software – it can run on most of the pins of the ESP-12. It’s a gimmick – but a nice one – and why not. On it’s own the LED ring is delicate and not that good looking – I still need to come up with some kind of casing or solution to maximise the EFFECT of the LEDs without showing the mechanics. As it happens I’m running it on one of our own little boards, a motherboard for an ESP-01 with nothing more than a couple of pullups, a 3v3 regulator and the ESP-01 socket.

      When I come up with a neat visual solution (or someone suggests a winner) I’ll put it in the blog for all to see.

    1. AHAH… this could be the first clue I’ve had. Lots of people thought C used 1 as the first item in an array which is wrong… but this could be worthy of investigation – first time I’ve seen this and thanks Luc.

      1. And thanks to this and other posts – YES – my mental vision of the % operator has been wrong all this time!!! So – a quick MOD function and it all works a treat. Many thanks.

  2. Peter:

    This could not be related to you issue but at midnight hour and minutes are 0 so x becomes 0 at line:

    int x=((hour12)+(tm.Minute/12))*3;

    In line:

    rgb.buffer[(x-8)%180]=5

    x-8 = 0-8 = -8. Indexing by -8 could lead to a memory violation.

    The same thing could happen at lines:

    rgb.buffer[(tm.Minute*3-3)%180]=8; // minutes green

    and

    rgb.buffer[(x-5)%180]=16;

    1. Can you enlighten me on this – I’ve always understood (and tested in Google though not in C) that the % modulus operator returns the remainder of a division – and that this would always be a positive number… hence 0%180 would be 0, -1%180 would be 179 etc… that’s how it pans out in a Google test “-1 modulus 180”. http://www.cprogramming.com/tutorial/modulus.html

  3. Are all the LEDs the same color at midnight? What color?
    Is everything good again at 1 second after midnight?

  4. The only thing I can think of is that at midnight it’s all zeros does that break something in the hours variable?

    1. Even with x == 0 your are subrating, means writing data below array begin.
      Not exactly sure why you do those x based writes and what is in that memory below, but as usual anything can happen.

Comments are closed.