nerdralph / picoCore

size-optimized Arduino/Wiring core for tiny AVR MCUs
MIT License
28 stars 4 forks source link

Is millis() a bit slow? #8

Open MCUdude opened 1 year ago

MCUdude commented 1 year ago

Hi!

I was going through some older MicroCore issues when I discovered that PicoCore had an updated version of your millis implementation that compiles down to a smaller size than the one MicroCore uses today.

Before copying your implementation, I decided to test how it performs compared to the one MicroCore uses today. I've been using a dedicated frequency counter and the code below for testing.

What's interesting is that with picoCore, the period time is 9.432 s, but with MicroCore, it's 7.958 s. I know the internal 128kHz oscillator isn't that accurate but is a deviation like this correct?

// Blink without Delay

// constants won't change:
const long interval = 4096;

void setup() {
  // set the digital pin as output:
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  static uint8_t ledState = LOW;
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(LED_BUILTIN, ledState);
  }
}
MCUdude commented 1 year ago

I realize now that I'm adding 19 every interrupt, while your code adds 16. I'm not familiar with assembly at all, so how can your code be modified to add 19 instead of 16? IIRC, I'm adding 19 because almost all ATtiny13 WDT oscillators are too slow.

MCUdude commented 1 year ago

@nerdralph do you have time to look at this? Your millis code is superior to the one that MicroCore uses, but as I explained earlier, would like to add 19 instead of 16.

nerdralph commented 1 year ago

One of the things I did with picoCore was to reduce interrupt latency and minimize the time spent in interrupts: less time in interrupts means more cycles available for user code. The original millis() asm code I wrote for MicroCore did the math (19 WDT interrupts per ms) inside the interrupt. picoCore just increments a 16-bit millis count (pinned to r2 & r3) in the interrupt, then does the multyply (x16 in this case) in the millis() code. I picked x16 because it is pretty close with the t85, and a lot less code than x19 due to the fact that x16 can be done with a few shifts.

I'll ruminate on it.

MCUdude commented 1 year ago

I'll ruminate on it.

Thanks! Please let me know if you come up with a solution that would work. After this, I'll probably release a new MicroCore boards manager version