LED Sequencer and an apparent timing issue (delays appear to solve the problem)


all-

so i'm working on led sequencer firmware lilypad clone on-board tlc5940.  idea user creates "banks" of 1 (or more) leds , interval each bank.  @ desired time, bank turn on (or off) needed.

these banks have been defined in eeprom (this stripped-down version of code; actual software supports "program mode" allow user configure eeprom serially via visual basic .net program) , read in @ run-time.

i setup pattern defined 6 banks of 2 leds, each firing @ 1/2, 1, 2, 4, 8, , 16 seconds (a 6bit binary counter).  interval defined in 1/10 seconds, max of 9999 (16 minutes , change).

the problem:  first bank turns on, doesn't turn off after 1/2 second.  blinks 1/2 second every 10 seconds or (if that).  other 5 banks work fine.

the (apparent) solution: added debugging statements figure out why didn't work , guess - problem disappeared!

finally messed around various combinations discover "delay(2)" in addevent method seems easiest , solution less impact (adding debugging code throws off animation).

so uncommenting define effin_buggy_code or debug_check cause problem disappear.

also if change delay @ bottom of loop() 25 millis or more problem doesn't appear either (but animation isn't smooth).

basically adding sufficient debug code see going on causes problem disappear.

so i'm assuming sort of timing issue buggy code, hence reason post.

first up, main program

code: [select]
// simple led sequencer code
#include "events.h"
#include <tlc5940.h>
#include <eeprom.h>

#define max_brightness      40               // max led brightness
#define eeprom_base        100               // start of bank data
#define size_of_eeprom       4               // size of bank data in eeprom

events sequencelist;                         // event queue

void setup() {   
  int bankoffset = 0;

  serial.begin(9600);
 
  sequencelist.init();                       // initialize event list

  // fetch data eeprom.  start w/ number of banks
  int numberbanks = eeprom.read(eeprom_base);

  // each bank, pull sequence info
  (int indx=0; indx < numberbanks; indx++) {
    // pull data each bank eeprom
     
    // first determine offset eeprom
    int spot   = eeprom_base + 1 + (size_of_eeprom * indx);

    int bankno     = eeprom.read(spot);
    int numberleds = eeprom.read(spot + 1);

    // handle interval bit differently since it's integer
    int interval   = eeprom.read(spot + 2) << 8;       // high byte
        interval  += eeprom.read(spot + 3);            // low byte

    // add these entries event list , let's go!
    sequencelist.addevent( interval, bankno, bankoffset, numberleds );
     
    // adjust bank offset
    bankoffset += numberleds;
  }

  // initialize tlc5940 , turn channels off
  tlc.init(0); 
}

// main program loop
void loop() {
  // pretty idle here waiting next event expire.  toggle
  // led state, delete event, , re-add new eventtime.
  if (sequencelist.checkevent()) {
    // timer expired!  extract details
    int banknumber = sequencelist.getbanknumber();
    int bankoffset = sequencelist.getbankoffset();
    int interval   = sequencelist.getinterval();
    int numberleds = sequencelist.getnumberleds();
    boolean lights = false;

    // delete , re-add event can keep things on schedule
    sequencelist.deleteevent();
    sequencelist.addevent(interval, banknumber, bankoffset, numberleds);

    // check first led in bank see if need turn off or on
    if (tlc.get(bankoffset) == 0)
      lights = true;

    // update bank needed
    (int indx = bankoffset; indx < (bankoffset + numberleds); indx++) {
      if (lights)
        tlc.set(indx, max_brightness);
      else
        tlc.set(indx, 0);
    }

    // update display
    tlc.update();
  }
  else {
    // let's kill time here
    delay(2);
  }
}


here included "events" class.

code: [select]
// events
// simple event handler led sequencer
#include <wprogram.h>

// total number of events possible
#define max_events 16

class events {
private:
  // event structure
  typedef struct {
    unsigned long eventtime;                     // event deadline
    int interval;                                // actual event time period
    int banknumber;                              // bank number
    int bankoffset;                              // bank offset (0-16)
    int numberleds;                              // total number of leds in bank
  } event;

  event eventlist[max_events];                   // current event list

  int numberevents;                              // number events in list
public:
  void init(void);                               // initialize object

  // add event list
  boolean addevent(int interval,
                   int banknumber,
                   int bankoffset,
                   int numberleds);

  // check see if current event has expired
  boolean checkevent(void);

  // fetch event details
  int getinterval(void)       { return eventlist[0].interval;}
  int getbanknumber(void)     { return eventlist[0].banknumber;}
  int getbankoffset(void)     { return eventlist[0].bankoffset;}
  int getnumberleds(void)     { return eventlist[0].numberleds;}

  // how many events in queue?
  int getnumberevents(void)  {  return numberevents;}

  // delete current event
  boolean deleteevent(void);
 
  void dumpevents(void);
};

//
// class implementation follows
//

// initialize object
void events::init(void) {
  numberevents      = 0;
}

// add event queue (ok, it's array).  note insert items
// in chronological order of expiration
boolean events::addevent(int interval, int banknumber, int bankoffset, int numberleds) {
  int indx = 0;
  boolean found = false;
  boolean done = false;
  unsigned long eventtime = millis() + (unsigned long)interval * 100ul;

  // make sure there room @ inn
  if (numberevents == max_events)
    return false;

#define effin_buggy_code 1
#ifdef effin_buggy_code
  // can't figure out how make work consistently without small delay
  // here.
  delay(2);
#endif

  // locate position in array
  (indx = 0; (indx < numberevents) && !found; indx++) {
    found = (eventtime < eventlist[indx].eventtime);
  }

  if (found) {
    // found spot in array.  move existing events 1 spot

    // first adjust indx (since off one)
    indx--;

    // move items 1 leave spot
    (int spot=numberevents; spot > indx; spot--) {
      eventlist[spot] = eventlist[spot - 1];
    }

    // insert new event
    eventlist[indx].interval         = interval;
    eventlist[indx].eventtime        = eventtime;
    eventlist[indx].banknumber       = banknumber;
    eventlist[indx].bankoffset       = bankoffset;
    eventlist[indx].numberleds       = numberleds;
  }
  else {
    // didn't find it.  add end of list
    eventlist[numberevents].interval   = interval;
    eventlist[numberevents].eventtime  = eventtime;
    eventlist[numberevents].banknumber = banknumber;
    eventlist[numberevents].bankoffset = bankoffset;
    eventlist[numberevents].numberleds = numberleds;
  }

  // bump event counter
  numberevents++;

  return true;
}

// check see if current event has expired
boolean events::checkevent(void) {
  if (numberevents == 0)
    return false;

//#define debug_check 1
#ifdef debug_check
  if (millis() >= eventlist[0].eventtime) {
    if (eventlist[0].banknumber == 1) {
      serial.print("expired @ ");
      serial.println(millis());
    }
  }
#endif 
  return (millis() >= eventlist[0].eventtime);
}

// delete current event
boolean events::deleteevent(void) {
  // make sure list populated
  if (numberevents == 0)
    return false;

  // if there 1 done here
  if (--numberevents == 0)
    return true;

  // move rest down bit
  (int indx=1; indx <= numberevents; indx++) {
    eventlist[indx - 1] = eventlist[indx];
  }

  return true;
}


ideas?  things can better?  far, thing i've thought of improve code's speed keep current led state in event structure (since i'm sure it's faster pull out boolean , flip query tlc5940 on spi).

thanks in advance,

brad (kf7fer)

ps oh yeah, i've tried faster animations (1/10, 1/5, 2/5, 4/5, 1.6, , 3.2 seconds) slower (1,2, 4, 8, 16, , 32 seconds) , problem persists.

i'd suggest of names misleading:
code: [select]
#define size_of_eeprom       4               // size of bank data in eeprom
my eeprom larger that. size_of_bank might better name.

code: [select]
    int spot   = eeprom_base + 1 + (size_of_eeprom * indx);
spot? how startaddress?

your class should have constructor calls init(), can assured init() gets called.

you deleteevent() method removes last event. don't design. should able remove nth event.

your checkevents() method returns true if event occurred. should return -1 no event, , n nth event.

your other methods assume first event in list event fired.

really, think problem in events class. need know event occurred, can data event. deleting event, , re-adding it, silly. add method reset nth event's eventtime value.


Arduino Forum > Using Arduino > Programming Questions > LED Sequencer and an apparent timing issue (delays appear to solve the problem)


arduino

Comments

Popular posts from this blog

Thread: PKI Client 5.00 install (for eToken Pro)

ATmega2560-Arduino Pin Mapping

Crossfader Arduino Tutorial