Go Down

Topic: Confusion with micros() (Read 2180 times) previous topic - next topic

essertier

Using Arduino mega & Linux, this code:

void setup() {
 unsigned long x;
 Serial.begin(115200);
 noInterrupts();
 x = micros();
 Serial.println(x);
 x = micros();
 Serial.println(x);
 x = micros();
 Serial.println(x);
 x = micros();
 Serial.println(x);
 x = micros();
 Serial.println(x);
 x = micros();
 Serial.println(x);
}

void loop() {
}

Gives me this output on the monitor:
428

928

1432

1068

1728

1364


Removing noInterrupts() yields a sequential output.  Keeping the noInterrupts(),
but changing baud rate to 57600 gives a sequential output.  Can somebody
explain what's happening?

AWOL

I think if you disable interrupts, anything related to time has to be suspect.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

westfw

micros() essentially computes "millis() + microseconds_since_last_millisecond_tick()", so if you break millis() (by turning off interrupts) it will also break, after about ... 1 millisecond.

essertier

Thank you westfw.  Your explanation makes sense.  I discovered the Almel spec sheet which has a thorough explanation of how the timers work, and now it is starting to come together.  I didn't know how micros() worked, until your post.

essertier

Well, I've gotten into this deeper than I wanted to.  The Timer1 and Timer3 code do not support a a one time timer (such as interrupt me in 1,234,567 usec), I needed just this--accurate to within 1 usec--which the Arduino supports quite nicely..  However, in verifying my code, i was using micros(), and discovered a problem with it.  This program below does nothing but read micros, but occasionally subsequent reads are lower than previous reads:

Code: [Select]


void setup(){
  unsigned long x, xLast=0, y = 0;
  int count = 0;
 
  Serial.begin(19200);
  while(true){
     x = micros();
     if (x < y){//This should never happen (except overflows)
        Serial.print(x);
        Serial.print(" ");
        Serial.print(y);
        Serial.print(" ");
        Serial.print(x - xLast);//Time between last error and this one
        Serial.print(" ");
        Serial.println(y - x);//Always the same difference
        xLast = x;
        count++;
        if (count > 100) break;//So no runaway
     }
     y = x;
  }
       
}

void loop(){
}

4100 5116 4100 1016

16388 17404 12288 1016

30724 31740 14336 1016

43012 44028 12288 1016

56324 57340 13312 1016

70660 71676 14336 1016

83972 84988 13312 1016

96260 97276 12288 1016

111620 112636 15360 1016

128004 129020 16384 1016

145412 146428 17408 1016

159748 160764 14336 1016

175108 176124 15360 1016

188420 189436 13312 1016

201728 202748 13308 1020



I looked at the micros() code very briefly, and noticed that it turns interrupts off while reading the overflow counter.  Would this turn the SIGNAL interrupt off, so that if there was an overflow while executing the micros code, wouldn't the overflow  be missed?  If so, maybe the code could check the overflow flag after it restores the interrupts.  I didn't study the micros() code very thoroughly, but clearly there is an important problem here.

The micros() function is one function that should behave reliably, because a lot of other code may be depending on it.

Coding Badly


Does your Sketch behave as expected if you make the variables global...

Code: [Select]
unsigned long x, xLast=0, y = 0;
int count = 0;

void setup(){

  Serial.begin(19200);
  while(true){
...

essertier

Global or local variables makes no difference.  It is a serious problem with the function.  As you can see, my code is utterly simple.  I was hoping it might be a conflict with the Serial output, but that is not it.  I tried basically the same thing but storing the data in an array, and then outputting as a batch...but I get the same data.  The problem is in micros().  It should be quite easy to diagnose, because it it very consistent.

Coding Badly


When I run your Sketch, I get no output.  I assume from the comment that's what is supposed to happen.

I'm using Arduino 0019 on Windows Vista.

essertier

Getting no output means you are getting no errors.  (If you scroll to the end of my code you will see sample output that I get.)  No output is what we want.  I'm getting suspicious that it is my hardware misbehaving--and not the micros code.  I just ran a loop on an array where I ask to output A and then B and then A - B.  I get what I expect for A and B, but then garbage for A-B (or A+B).  And then 20 elements later, I get good stuff again.  It can't be memory, because it is computing the result.  Hmmm....

Thanks for your input.  Don't spend anymore time on this problem (micros) until I can verify my hardware.  I'm a very experienced C++ programmer, but kinda new to Arduino...still learning what to expect.  I'm very impressed with what it can do.

Here's a really stupid question:  How do you tell which Arduino Mega you have by looking at it?  Also how much programming space (code, variables, stack) do I have?  The compiler says I have 128k...is that how much I really have to work with, or is it something less?  My code right now is about 11k according to the compiler.

PaulS

Quote
Also how much programming space (code, variables, stack) do I have?  The compiler says I have 128k...is that how much I really have to work with, or is it something less?  My code right now is about 11k according to the compiler.

There are 3 different kinds of memory on the Arduino - EEPROM, Flash, and SRAM.

The 128K on the Mega refers to the amount of flash memory you have. There is 8K of SRAM too. Constants, strings, stack data, etc. goes in SRAM.

It is possible to run out of SRAM while still having loads of space in flash, if you have lots of strings or large arrays.

alisontin

Wow, this thread is really great, post here are very educational and helpful.  Thanks for the post.

essertier

So now I think I understand now (thanks to PaulS post) how the memory is managed with the Arduino.  Maybe this is described somewhere else, but in summary here is what I learned by fiddlin around:

There are 3 address spaces.  The SRAM (8k) starting from top of memory has:

Declared constants (from all your code)
1st stack frame:  Return ptr
                            Local arrays
                            Local variables
Next frame:         Return ptr
                            Local arrays
                            Local variables
                           ....
                           <free mem>
                           ....
Global variables

In a different address space you have your code which might be up to128 or 256k.

And then in a third address space you have EEPROM (4k) which you can
read/write for persistent data.

For designing applications, this means:
1.  Be very frugal with SRAM.  This means keep arrays as small as possible, keep globals to a minimum, send your generated data somewhere else--don't use SRAM to keep it for you.  The EEPROM should be used only for what you really want to persist, because you don't have much space, and it is a little awkward (and slower) to access.
2.  You can be reckless with the size of your code.  It would be hard to consume 128k, much less 256 with code.

How much memory is left in SRAM?  I don't know if libray functions exist, but this little snippet I did yesterday works for me:

int availableMemory(){
  int loBound = (int)&lastDeclaredGlobalVariable;
  int hiBound = (int)&hiBound;
  return hiBound - loBound;

Globals are stored working up from the bottom of memory.  Use whatever variable (outside of any function) which was last declared for the function above.  The stack is working down from the top of memory.  So the last declared local variable is the top of the available space--in this case it would be hiBound itself.  The difference between these two addresses tells you how much you have at the time of the availableMemory() call.

What happens when the stack meets the lower bound?  Your program freezes, and Arduino blinks one of the lights.

I hope this helps somebody.  Arduino is all new to me, so if I said something wrong here please post a correction!

westfw

Quote
What happens when the stack meets the lower bound?  Your program freezes, and Arduino blinks one of the lights.

Only if you're lucky.  If you're unlucky you program will start doing weird things without given any outward indication of why!

The thing that really bites most people that that constant strings end up using RAM space:
  Serial.print("..........0123456789..........");
30+ bytes of ram used to hold a constant, for no particularly good reason (well, the compiler says it must...)
There are ways to put such strings in Flash instead, but it's generally somewhat complicated.

essertier

I absolutely concur with the constants comment.  As it stands there is no way to enter constant tables.  With a tweek of the compiler, and no hardware changes, one could enter lookup tables into flash memory, that is currently not used, and that might speed up processing a lot.  I can think of many applications that would be impossible without this feature.

Is there a (practical) way to extend SRAM?  Or is there something that can be added to provide more RAM without going through the serial port?

westfw

Quote
As it stands there is no way to enter constant tables.

Sure there is.  It's just a little more complicated.  Check out the Flash library implemented for Arduino: http://arduiniana.org/libraries/flash/ or the tutorial , or the "barer" AVR Freaks Tutorial: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003

Quote
With a tweek of the compiler, and no hardware changes, one could enter lookup tables into flash memory, that is currently not used, and that might speed up processing a lot.

It's not that easy.  Given a pointer (which is a fundamental thing inside of C and C++, even if you don't use pointers explicitly) with a value of, say 1000, there is no way to tell whether that points to RAM, EEPROM, or Flash...

Go Up