Hallo Joe,
ich versuche mich mal am Assembler Teil:

Da wird in C mit Inline Assembler in einer Schleife eine Millisekunde versucht zu
erzeugen. Bei 128kHz ist ein Maschinenzyklus 1/128000Hz = 7,8125µs lang. Die Sequenz
3a: 31 97 sbiw r30 , 0x01
3c: f1 f7 brne .-4 ; 0x3a

subtrahiert von dem, in der Routine eingestellten Wert 26 (uint16_t __c = 26 ) den Wert eins solange, bis dieser 0 ist. 25 Subtraktionen und Sprünge auf Adresse 3a brauchen je 4 Zyklen. 4 * 25 * 7,8125 sind 781,25µs + 23,1375 = 804,6875µs. 3 * 7,8125µs = 23,1375µs für den letzten Schleifendurchlauf ohne Sprung.

Wenn 26 auf 0 runtergezählt ist, wird vom übergebenen Millisekundenwert eine Millisekunde abgezogen, und wenn nicht Null, dann Sprung auf 0x38 und wieder eine knappe Millisekunde (0,804..ms) Wartezeit erzeugt. Dafür wird bei Adresse 0x38 zunächst wieder der Wert 26 mit movw herausgekramt und dann wieder die Warteschleife durchlaufen. Jedes sbiw verschlingt 2 Maschinenzyklen. Der nachfolgende Vergleich mit Sprung auf 3x38 auch nochmal 2 Zyklen. Um zu ergründen, warum da mal eine 0 abgezogen wird, müßte man tiefer in asm einsteigen. Möglicherweise richten des Carry Flags.

Justierung der genauen Millisekunde also am Wert von uint16_t __c unter Berücksichtigung des Maschinentaktes.

Code:
00000032 <wms>:
    for(; ms>0; ms--) 
    {                           //
    uint16_t __c =  26;         // Ergibt am 14Dez21,17h34 1,001 sec bei wms=1000
                                // => bei wms ( 100) ist der (periphere) Einfluss
                                //      des Programmablaufs deutlich messbar !!
      __asm__ volatile (        //
** der Wert 26 wird als 2 Byte in die Prozessorregister 18, 19 geladen.
  32:    2a e1           ldi    r18, 0x1A    ; 26
  34:    30 e0           ldi    r19, 0x00    ; 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  void wms ( uint16_t ms )      // 128 kHz-wms; Pausenwert ist nur experimentell !
                                //      M E I S T   keine Millisekunde ! ! !
// - - - - - - - - - - - - - - - -
  {                             // Weiter Messwerte in L3_tmr10.c und früher
    for(; ms>0; ms--) 
  36:    04 c0           rjmp    .+8          ; 0x40 <__SREG__+0x1>
    {                           //
    uint16_t __c =  26;         // Ergibt am 14Dez21,17h34 1,001 sec bei wms=1000
                                // => bei wms ( 100) ist der (periphere) Einfluss
                                //      des Programmablaufs deutlich messbar !!
      __asm__ volatile (        //
** der Wert 26 wird aus r18, r19 nach r30, r31 übertragen
  38:    f9 01           movw    r30, r18
** Beginn der Schleife für eine ms
  3a:    31 97           sbiw    r30, 0x01    ; 1
** Sprung nach 3a wenn noch nicht Null
  3c:    f1 f7           brne    .-4          ; 0x3a <__CCP__+0x6>
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  void wms ( uint16_t ms )      // 128 kHz-wms; Pausenwert ist nur experimentell !
                                //      M E I S T   keine Millisekunde ! ! !
// - - - - - - - - - - - - - - - -
  {                             // Weiter Messwerte in L3_tmr10.c und früher
    for(; ms>0; ms--) 
** Abzug von eins vom übergebenen Millisekundenwert, der sich anscheinend in r24, r25 befindet.
  3e:    01 97           sbiw    r24, 0x01    ; 1
  40:    00 97           sbiw    r24, 0x00    ; 0
** Wenn übergebener ms Wert noch nicht Null, dann nochmal Sprung zur 1ms Laufschleife
  42:    d1 f7           brne    .-12         ; 0x38 <__CCP__+0x4>
         "1: sbiw %0,1" "\n\t"  //      schwankt >> mit Temperatur ! ! !
         "brne 1b" 
         : "=w" (__c)          : "0" (__c) 
      ); 
    } 
  }
** Rücksprung zu Aufrufort
  44:    08 95           ret

00000046 <main>:
// =============================================================================

Gruß
Searcher