Rahix / avr-hal

embedded-hal abstractions for AVR microcontrollers
Apache License 2.0
1.32k stars 223 forks source link

New Timers #151

Open Rahix opened 3 years ago

Rahix commented 3 years ago

This issue serves to track efforts on re-designing the timer API as part of #130. As a first step, I think we should gather a list of "use-cases" that should be supported:

Cc: @koutoftimer

andrewshadura commented 3 years ago
mutantbob commented 2 years ago

Is there an API that translates from the data sheet to the register writes? Right now I have code that does

tmr1.tccr1a.write(|w| w.wgm1().bits(0b00));
tmr1.tccr1b.write(|w| {
    w.cs1()
        //.prescale_256()
        .variant(CLOCK_SOURCE)
        .wgm1()
        .bits(0b01)
});
tmr1.ocr1a.write(|w| unsafe { w.bits(ticks) });
tmr1.timsk1.write(|w| w.ocie1a().set_bit()); //enable this specific interrupt

It would probably be more readable if it looked like

let timer1 = Timer::wrap(dp.TC1);
timer1.set_clock_select(CS1_A::PRESCALE_256);
timer1.set_waveform_generation_mode(WaveformGenerationMode::CTC_OCR1A);
timer1.set_output_compare_register_1a(ticks);
timer1.set_output_compare_a_match_interrupt_enable(true);

or maybe

let timer1 = Timer::configure_and_enable_timer(
    &dp.TC1,
    CS1_A::PRESCALE_256,
    WaveformGenerationMode::CTC_OCR1A,
    ticks,
);

Although I am certain that the example code I provided drastically oversimplifies the options.

I assume this code will look a little different for each AVR implementation unless they all have the same register layout.

mutantbob commented 2 years ago

A quick review of the datasheets for the atmega328p (https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf) and the atmega2560(https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf) shows:

328p: 8-bit timer (TC0, section 14.9) 16-bit timer ( TC1, section 15.11 ) 8-bit timer w/ async-op (TC2, section 17.11 )

2560: 8-bit timers (TC0, section 16.9) 16-bit timers (TC1,3,4,5, section 17.11 ) 8-bit timer w/ async-op (TC2, section 20.10 )

When comparing the registers on the 328p and the 2560 one thing that jumps out is that the 2560 has A, B, and C (section 17.11.17-28) comparators on its 16-bit timers, while the 328p only has A and B (section 15.11.5&6).

I was hoping that the two models could be unified by some traits, but it will not be as clean as I initially hoped. I'm also unsure how this timer architecture generalizes across the other AVR implementations.

mutantbob commented 2 years ago

I have created a couple of timer experiments that I hope to turn into examples for the avr-hal project:

https://github.com/mutantbob/avr-timer/blob/master/led-pwm/src/megalovania.rs uses PWM and a buzzer to play a chiptune

https://github.com/mutantbob/avr-timer/blob/master/led-pwm/src/led-pwm.rs uses PWM with a duty cycle to control LED brightness.

If these apps are suitable use cases for the arduino-uno examples, let me know what changes are needed to bring them to their final form. It is also possible that they can serve as uses cases to drive a more friendly timer API.