Repository navigation
Conversation
| overflows = 0; | ||
| TC0.TIFR0.write(.{ .TOV0 = 1, .OCF0A = 0, .OCF0B = 0 }); // writing 1 clears it | ||
| TC0.TIMSK0.write(.{ .TOIE0 = 1, .OCIE0A = 0, .OCIE0B = 0 }); | ||
| TC0.TCCR0B.write(.{ .CS0 = .RUNNING_CLK_64, .WGM02 = 0, .FOC0B = 0, .FOC0A = 0 }); |
There was a problem hiding this comment.
Why 64 prescaler? At 8MHz that gives a 2uS-ish granularity. With 32 we get a nice 1uS-ish. Have you looked at how many cycles the overflow interrupt takes? Obviously with 32 we'd be paying that cost twice as often.
There was a problem hiding this comment.
Also, this isn't connected to prescaler at all which puts us as risk of someone configuring that global while it not actually having any bearing on the tick frequency.
There was a problem hiding this comment.
Timer0 supports /1, /8, /64, /256 and /1024; /32 and /128 are available on Timer2. With /64, ticks are 8 µs at 8 MHz and 4 µs at 16 MHz. /8 gives 1 µs at 8 MHz, but 0.5 µs at 16 MHz, which this HAL's whole-microsecond tick conversion doesn't support.
The ReleaseSmall disassembly gives 86 cycles for the ISR, or 93 including interrupt entry and the vector jmp. That's about 0.57% CPU with /64 versus 4.54% with /8. I'd keep /64.
On the second point: good catch. CS0 now derives from prescaler through a comptime switch, and unsupported Timer0 divisors cause a compile error.
There was a problem hiding this comment.
ah, I assumed there was /32 in timer0. Two uS should be fine.
|
|
||
| /// Microseconds per tick at `cpu_frequency`, or null if that isn't a whole | ||
| /// power of two. | ||
| fn find_us_per_tick(cpu_frequency: u32) ?u32 { |
There was a problem hiding this comment.
could make this explicitly comptime
There was a problem hiding this comment.
actually shouldn't matter, we can make the one call that isn't a test an explicitly comptime call.
There was a problem hiding this comment.
Done, made cpu_frequency explicitly comptime.
|
Wait so you sat there for an entire minute counting the number of times the LED blinked? |
|
Guilty. Most suspenseful minute of my week :) It only catches gross errors though (a wrong prescaler or tick size is 2x off), so I measured it properly too. A test firmware prints
Both methods agree on each board, so Happy to share the firmware and the script if they're useful. |
Adds
hal.timefor the ATmega328P using Timer0. Part of #1069; the timer is opt-in, as discussed there.init,get_time_since_boot,sleep_msandsleep_us. Time is measured frominit.hal.time.timer0_overflowforTIMER0_OVF, callsinitand enables interrupts.initchecks the handler registration at compile time. AVR does not use HALdefault_interrupts, so registration is explicit. Without initialization, Timer0 remains available for PWM on D5/D6.find_us_per_tick.sleep_msuses 1 ms chunks to avoid runtime 64-bit multiplication. Sleeps require interrupts enabled. The overflow handler must run within one overflow period: 1.024 ms at 16 MHz or 2.048 ms at 8 MHz.blinky_timefor the Nano, Pro Mini 3.3 V and RF-Nano V3.Hardware-tested on an Emakefun RF-Nano V3.0 (16 MHz) and an Arduino Pro Mini 3.3 V (8 MHz). The example toggles the LED with
sleep_ms(500)between toggles. On each board, I counted 60 LED turn-ons over a manually timed 60-second interval.Inspected the example ELFs: vector 16 points to the Timer0 overflow handler, which returns with
reti, and no compiler_rt helpers are linked.