Jump to content
43oh

micros() function gives low resolution


Recommended Posts

If I try to read the "micros()" function, I only get multiples of 512.

I run a MSP430G2553 that, according to specs, should run with 16MHz.

here is a minimalistic code:

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  Serial.println(micros());
}
Any ideas why I can not get higher resolution than 512 uSec?

 

 
cheers, Daniel
Link to post
Share on other sites

Turn on verbose compile. Find out where your .elf is written. Open a command window. chdir to that place. Then decompile the code to see what is really going on.

 

msp430-objectdump -CS sketch_name.cpp.elf

 

Look at the instructions that takes. You don't get all that convenience for free. There are lots of instructions going on there.

 

A better test would be putting a scope on the blinking red led and run it in a tight loop.

 

void setup() {
  P1DIR |= BIT0;
  P1OUT |= BIT0;
}

void loop() {
  do {
    P1OUT ^= BIT0;
  } while(1);
}

That code is as good as it gets and you will see it doesn't even come close to 16MHz
Link to post
Share on other sites

On MSP430 microseconds are counted up by a timer interrupt. As it's unpractical to have 1 million interrupts per second, this happens in larger steps.
 
From the source code

	// MSP430 does not give read access to current WDT, so we
	// have to approximate microseconds from overflows and
	// fractional milliseconds.
	// With an WDT interval of SMCLK/512, precision is +/- 256/SMCLK,
	// for example +/-256us @1MHz and +/-16us @16MHz

	return (m * MICROSECONDS_PER_WDT_OVERFLOW);

Actually, the comment is not 100% correct, as the code simply multiplies the number of WDT overflows (m) with the microseconds per overflow. So MICROSECONDS_PER_WDT_OVERFLOW defines the discrete steps in which micros() is available.

MICROSECONDS_PER_WDT_OVERFLOW is definied further up:

// the clock source is set so that watch dog timer (WDT) ticks every clock
// cycle (F_CPU), and the watch dog timer ISR is called every 512 ticks
// for F_CPU < 8MHz and every 8192 ticks for F_CPU > 8MHz.
#if F_CPU < 8000000L
#define TICKS_PER_WDT_OVERFLOW 512
#else
#define TICKS_PER_WDT_OVERFLOW 8192
#endif

// the whole number of microseconds per WDT overflow
#define MICROSECONDS_PER_WDT_OVERFLOW (clockCyclesToMicroseconds(TICKS_PER_WDT_OVERFLOW))

Interpreting the above:
F_CPU in your case is 16 MHZ, which is larger than 8 MHZ, so the timer is set to 8192 clock cycles per interrupt. 8192 cycles / 16 MHz translates to an interrupt (WDT overflow) every 512 microseconds.

Link to post
Share on other sites

I can see scenarios where more precise micros() would be helpful, e.g. when trying to time the arrival of a signal. Something within 10 microseconds should be achievable even in a dumb loop.

 

On bare metal I'd use a dedicated timer that counts up (or down) on every clock cycle. Stop it and read its value when the event occurs. Add an interrupt routine if you need to handle overflows. I don't know if there's an Energia library that neatly packs this up.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...