I'm going to be writing some performance critical code and have started trying to get an understanding of timers and how much "work" the Due CPU can do per second. To help get started with this, I wrote a bare sketch that simply increments a counter whilst a timer which ticks every second dumps the value of the counter to the serial log and then resets the counter. Here's the code I'm using:
#include <Arduino.h>
void EnableTimer7TickEverySecond();
volatile uint32_t gCounter = 0;
void setup()
{
Serial.begin(9600);
EnableTimer7TickEverySecond();
// while ( true )
// {
// ++gCounter;
// }
}
void loop()
{
++gCounter;
}
void EnableTimer7TickEverySecond()
{
pmc_set_writeprotect(false);
pmc_enable_periph_clk(ID_TC7);
TC_Configure(TC2, 1, TC_CMR_WAVE |
TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1);
TC_SetRC(TC2, 1, 656000 * 64);
TC_Start(TC2, 1);
TC2->TC_CHANNEL[1].TC_IER = TC_IER_CPCS;
TC2->TC_CHANNEL[1].TC_IDR = ~TC_IER_CPCS;
NVIC_EnableIRQ(TC7_IRQn);
}
void TC7_Handler()
{
TC_GetStatus( TC2, 1 );
Serial.println( (uint32_t)gCounter );
gCounter = 0;
}
When I run this, I get values averaging 446,000 in the serial log for the increments per second. That is way lower than I was expecting. On an ARM chip running at 84MHz, I'd expect at least 14 million increments as few ARM instructions take more than 2 clock cycles and an increment should involve a read from memory, addition and a write back to memory (approx 6 clock cycles by my reckoning).
The timer is configured correctly, the TX led flashes regularly at 1 second intervals as the Serial.println is called. I've checked for overflow on the counter (oddly, I found that the number of increments when working with a uint64_t was slightly higher). I've also tried not calling Serial.begin() until I'm about to write the value to the log (and then only writing the value once) and whilst there is a slight increase in "performance", it doesn't account for the whole difference between expectation and reality.
My best guess would be that loop() is called on some sort of timer or has a built in default delay, so it occurred to me that if I comment out the counter increment in loop() and instead comment in the infinite while loop in setup(), I should be able to counteract any delay caused by how frequently the Arduino IDE calls loop(). I have seen other examples that never bother with loop() and just stick all their code in setup().
I do see a performance increase with this setup, but only to around 9 million, not the 14+ million I would expect. Oddly though, sometimes, randomly, the value is 2 or 3 times the "usual" value. Not between 2 and 3 times, but exactly 2 or 3 times. This happens regardless of whether I am incrementing the counter inside the loop() function or my own loop inside setup(). It is not a case of the timer "skipping", the output is written every second like clockwork.
So, my questions are:
What does the Arduino library do to make loop() so inefficient?
Is there any harm in keeping all your code inside an infinite loop in setup() and never returning out of it?
Why would I sometimes see the number of increments being 2 or 3 times higher than usual? Could the counter be getting cached (despite being marked as volatile) and not reset properly? If so, how can I prevent this?