Libraries and clock frequency

At least millis() is badly-implemented. I need to dynamically change the clock frequency. Well under 1MHz for normal operation (powered by a coin cell). Up frequency to 2MHz if I need to write to the EEPROM. But never, ever, using a fixed clock frequency. Why doesn't millis() handle this properly? Where can I find the sources so I can build a millis() that actually works when the clock frequency is not fixed?

Where can I find the sources so I can build a millis() that actually works when the clock frequency is not fixed?

Which core?

Edit: Wait a minute:

Retired Ph.D. in Computer Science

Seriously?

Use grep/grepwin and search the Arduino installation directory to find the implementation of millis()'

There's a variable called F_CPU that's predefined for the processor speed specified in your bootloader. It's possible you could change that value to whatever you select, such as 1000000, and the millis() function would notice. But I don't remember whether the Timer-0 ISR goes beyond the 8MHz and 16MHz settings. Anyway, I think it's all in wiring.c.

Of course you could always write your own. Here's one I did. I think you would just need to adjust the prescaler for different F_CPU values.

/*
This is a replacement for the ISR(TIMER0_OVF_vect)
interrupt that drives millis(). It disables the OVF
interrupt, enables the COMPA interrupt, sets OCR0A to 249,
and changes Timer0 to CTC mode.  This results in an
interrupt every 250 timer clock cycles, which is exactly 1ms
for a 16MHz crystal, or 2ms for an 8MHz crystal.  The new ISR
increments millis, but since the interrupt rate is exactly
correct, no periodic double increment of millis is needed.

Using this code probably means you can't do any analog
writes that use Timer0, which would include pins 5 and 6.
*/

extern volatile unsigned long timer0_millis;   //these defined in wiring.c
extern volatile unsigned long timer0_overflow_count;

volatile unsigned long MILLIS_INCB = (64 * 250) / (F_CPU / 1000);  // ms between timer overflows

const int cycleTime = 500;                 // flash LED every second
int LEDcount = cycleTime;
unsigned long oldMillis = millis();
unsigned long newMillis = 0;

void setup() {                             //Set up alternate interrupt
                                           //   at 249 on timer0
                                           
  cli();                                   // disable interrupts while doing this

  TCCR0A = 0;                              // set entire TCCR0A register to 0
  TCCR0B = 0;                              // same for TCCR0B
  TCNT0  = 0;                              // initialize timer0 count to 0

  OCR0A = 249;                             // set top of counter
  TIMSK0 &= ~bit(TOIE0);                   // disable overflow interrupt
  TCCR0A |= bit(WGM01);                    // turn on CTC mode
  TCCR0B |= (bit(CS01)+bit(CS00));         // Set CS00&CS01 bits for prescaler = 64
  TIMSK0 |= bit(OCIE0A);                   // enable timer compare interrupt

  sei();                                   // enable interrupts

  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

}


void loop() {                               // flashes LED for 1/2 second
                                            //    every second

  newMillis = millis();
  if ((newMillis - oldMillis) > 0) {
    oldMillis = newMillis;
    LEDcount -= 1;
    if (LEDcount == 0) {
      digitalWrite(13,!digitalRead(13));    // invert pin 13 state
      LEDcount = cycleTime;
    }   
  }
}


ISR(TIMER0_COMPA_vect) {                    // this is the new ISR - much
                                            //   simpler than original
  
  timer0_millis += MILLIS_INCB;
  timer0_overflow_count++;

}

Why doesn't millis() handle this properly

It wasn't part of the design.
Since the Arduino libraries do not provide a mechanism for changing the clock speed, they do not "need" a millis() implementation that supports changing the clock speed.

Where can I find the sources so I can build a millis() that actually works when the clock frequency is not fixed?

(that's for an AVR. The exact location on your system depends on your OS and exactly which versions of the IDE and Core you have installed. But it should always be in "wiring.c" - you can find the exactly location by looking at the build log after enabling "verbose" for compilation in the preferences dialog.
The megaAVR core ("Nano Every", "Uno WiFi 2") actually contains an example that handles clock rates determined at runtime (and perhaps variable?)

(at the expense of making the timer ISR rather slow and bloated :frowning: )