Millis() returns 0 - Need Help!

Hello,

I have a library that I got off the internet. It allows me to control RGB LED modules. The library makes use of the timer 1 to send data.

My problem is that I can't get millis() to work in my loop(). I am assigning millis() to a long int and then printing the value and it is always 0! I think it has something to do with the library's timer and interrupt routines. I can't figure it out though.

I have an arduino pro mini and I am outputting to 2 strands of 100 LEDs each.

Please help!

This is what is in the library I am using:

// Globals used by interrupt code.
char  SendMode=0;   // Used in interrupt 0=start,1=header,2=data,3=data done
char  BitCount=0;   // Used in interrupt
char  LedIndex=0;   // Used in interrupt - Which LED we are sending.
char  BlankCounter=0;  //Used in interrupt.
unsigned int BitMask;   //Used in interrupt.

LEDPixels LP1;              //Preinstatiate

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  LP1.doOutput();
}

void LEDPixels::show()
{
  // The interrupt routine will see this as re-send LED color data.
  SendMode = 0;
}

void LEDPixels::initialize(long microseconds, int * DisplayAddress,unsigned int LEDCount , char clkPin, char dPin, char dPin2 )  //MRW - for 2nd data pin (the last argument)
{

  byte Counter;

  clockPin = clkPin;
  dataPin = dPin;
      dataPin2 = dPin2; //MRW - for 2nd data ping
  Display = DisplayAddress;
  NoOfLEDs = LEDCount;

  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

                                        // Adjust as you please. Too slow makes LEDs flicker.
                                        // Too fast and the interrupt may chew into your processing speed!
    //Timer1.attachInterrupt( LedOut ) ;  // attaches routine to drive LEDs
    show();                             // Kick off display.


  TCCR1A = 0;                 // clear control register A 
  TCCR1B = _BV(WGM13);        // set mode as phase and frequency correct pwm, stop the timer

   if(microseconds > 0) setPeriod(microseconds);
  //isrCallback = isr;                                       // register the user's callback with the real ISR
  TIMSK1 = _BV(TOIE1);                                     // sets the timer overflow interrupt enable bit
  sei();                                                   // ensures that interrupts are globally enabled
  start();
}


void LEDPixels::setPeriod(long microseconds)
{
  long cycles = (F_CPU * microseconds) / 2000000;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  ICR1 = pwmPeriod = cycles;                                                     // ICR1 is TOP in p & f correct pwm mode
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                                     // reset clock select register
}


void LEDPixels::doOutput()
{
 switch(SendMode)
  {
    
    case 3:                        //Done..just send clocks with zero data
      digitalWrite(dataPin, 0);    //You'll need 255 clocks for a LED to diplsay 1 color pwm.
      digitalWrite(dataPin2, 0);    //MRW - for 2nd data pin
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
    case 2:               //Sending Data
      if (BitCount==0)    //First bit is always 1 followed by 15 bits of LED color.
        {  
                  digitalWrite(dataPin, 1);
                  digitalWrite(dataPin2, 1); //MRW - for 2nd data pin
            BitMask=0x8000;//Init bit mask
        }
      else 
        {
              if(BitMask & Display[LedIndex])  //If not the first bit then output the next bits (Starting with MSB bit 15 down.)
              {
                    digitalWrite(dataPin, 1);
              }else
              {
                    digitalWrite(dataPin, 0);
                    
                    //MRW - this entire if-else block is for the 2nd data pin
                    if(BitMask & Display[LedIndex+100])  //If not the first bit then output the next bits (Starting with MSB bit 15 down.)
                    {
                                              digitalWrite(dataPin2, 1);
                    }else
                    {
                                              digitalWrite(dataPin2, 0);
                    }
                    //end of new code
              }
              

        }
      
      BitMask>>=1;
      BitCount++;
      
      if(BitCount == 16)    //Last bit?
      {
        LedIndex++;        //Move to next LED
        if (LedIndex < NoOfLEDs) //Still more leds to go or are we done?
        {
          BitCount=0;      //Start from the fist bit of the next LED             
        }
        else
          SendMode=3;  //No more LEDs to go, we are done!
      }
      // Clock out data.
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;      
    case 1:            //Header
        if (BitCount < 32)              
        {
        digitalWrite(dataPin, 0);
        digitalWrite(dataPin2, 0); //MRW - for 2nd data pin
        BitCount++;
        if(BitCount==32) 
          {
            SendMode++;      //If this was the last bit of header then move on to data.
            LedIndex=0;
            BitCount=0;
          }
        }
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      
      break;
    case 0:            //Start
      if(!BlankCounter)    //AS SOON AS CURRENT pwm IS DONE. BlankCounter 
      {
        BitCount=0;
        LedIndex=0;
        SendMode=1; 
      }  
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      
      break;   
  }
  //Keep track of where the LEDs are at in their pwm cycle. 
  BlankCounter++;
}

void LEDPixels::start()
{
  TCCR1B |= clockSelectBits;
}

having little experience in the "lower" level programming.

according to - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200662708 (reply #2) - millis uses timer 0 . the context is Arduino 2009. on a pro mini it may differ.

Can you post the code of your application too? optional stripped to a version that still shows the problem.

Essentially, all I am doing in my main is:

LEDPixels LP;
LP.initialize(CLOCK_SPEED, &suit_left[0], TOTAL_LEDS_LEFT, 
CLOCK_PORT, DATA_PORT_LEFT, DATA_PORT_RIGHT);
Serial.begin(38400);   
currentMillis = millis(); 
Serial.println(millis());

And millis() will print just 0's. It won't increment.

So, I did some more testing, it seems that when I comment out the LP1.doOutput() in the ISR, it works fine and outputs values for millis().

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  int a; //just so the ISR is doing something
  //LP1.doOutput();
}

Perhaps the doOutput() function is too long? I read somewhere that timer0 won't increment while it is in an ISR. What if I just made the ISR set a flag and then my main checks the flag then runs doOutput()?

Example:

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
   interrupted_flag = 1;
}

then in the main

void loop(){
   if (interrupted_flag == 1)
   {
     interrupted_flag=0;
     LP.doOutput();
    }
   //rest of code goes here
}

That didn't work. It must of threw off the timing or something. Any ideas anyone? Here is my main code:

//define Arduino pinouts
#define DATA_PORT_LEFT 5//yellow
#define CLOCK_PORT 4 //green
#define DATA_PORT_RIGHT 3

//define LED settings
#define TOTAL_LEDS_LEFT 200  //on left half
#define CLOCK_SPEED 25

//Sequence Global Variables
unsigned int seq_counter = 0;

//Timing variables for sequence speeds without using delay()
//Variables are long because the time, measured in miliseconds, 
//will quickly become bigger than can be stored in an int
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long currentMillis = 0;         // will store the current time
unsigned int interval = 100;             //interval (milsec) before next LED output


// LED array
int suit_left[TOTAL_LEDS_LEFT];
LEDPixels LP;    //LED  controller object


unsigned int sequence_id = 0;
unsigned int sequence_params[NUMBER_OF_PARAMS];
unsigned int count_from_serial=0; //count how many bytes we have read in over serial


// LED Assignment

unsigned int Rows[] =  //numbers of LEDs

void setup()
{
  LP.initialize(CLOCK_SPEED, &suit_left[0], TOTAL_LEDS_LEFT, CLOCK_PORT, DATA_PORT_LEFT, DATA_PORT_RIGHT);

  //turn off all LEDs
  LP.setRange(0, TOTAL_LEDS_LEFT, 0);



  Serial.begin(38400);   
  Serial.println("All is set up and ready to go");
}

void loop()
{
 
  seq_rings();
}

void seq_rings()
{

  if(interval_ready())
  {

    
  Serial.println("now executing rings");


  /*unsigned char Rows_Ranges[] = {0,3,11,15,23,27,35,39,47,51,59,63,71,77,85,  // 0-13   Pants
   91,99,105,113,119,127,133,141,151,159,             // 14-23  Shirt
   163,167,171,175,179,183,187,191,193,197};                       // 24-33  Sleeves 
   */

  unsigned int q;


  if(seq_counter >199){
    seq_counter=0;
  }
  LP.setLEDFast(Rows[seq_counter], 55);
  seq_counter++;
  LP.show();
  //delay(100);
  }
}

int interval_ready(){

  currentMillis = millis();  //get current time from start of program in milliseconds
  if (currentMillis - previousMillis < interval){ 
    //not enough time has passed
    
    Serial.print("Not Ready Yet: ");
    Serial.println(currentMillis - previousMillis);
    return 0; 
  } 
  else { //time has exceeded interval, so it is ready
  Serial.println("interval ready");
    previousMillis = currentMillis;
    return 1;
  }


}

void loop() {
seq_rings();
}

void seq_rings() {
if(interval_ready())
...

int interval_ready(){
currentMillis = millis(); //get current time from start of program in milliseconds
if (currentMillis - previousMillis < interval){
//not enough time has passed
Serial.print("Not Ready Yet: ");
Serial.println(currentMillis - previousMillis);
return 0;
}

Arduino isn't a supercomputer but I still bet it can execute this at a pretty good clip! Are you sure you want to print that every loop?

in my main

Are you using the Arduino environment, with setup() and loop(), or are you using something else with your own main() function?

If you're doing the latter, none of the timer0/millis stuff will get initialized; they're normally initialized in a main() function provided by the arduino environment that looks like:

main()
{
   init();    // provided by arduino core as well
   setup();  // the function in the user's sketch
   for (;;)
      loop();  // other function from the user's sketch
}

I was only having it print that every loop for troubleshooting reasons, so I can see what it is doing.

Yes, I have the typical loop() and setup(). I was just referring to it as my main file as opposed to the library file.

I figured it out! Apparently, the interrupt was running twice as long as it should have because of a tiny tiny tiny little bug in the code where I wasn't dividing by 2 so it was running again.

Since the interrupt was running longer than it should, the Timer0 never got time to increment, therefore millis() never incremented.

Thanks for all your help.

I needed this ">> 1" since I am outputting to 2 strands in parallel.

 if (LedIndex < NoOfLEDs >> 1) //Still more leds to go or are we done?
        {
          BitCount=0;      //Start from the fist bit of the next LED
        }
        else
          SendMode=3;  //No more LEDs to go, we are done!
      }

a tiny tiny tiny little bug

But alas still a bug. :wink: