finished timer code; now using in main()

untested, but it should work.  i'll test before pushing to github, and
update if i messed anything up
partial-rewrite
Ben Blazak 2013-05-06 23:25:41 -07:00
parent 5e1877cb82
commit a7d11e0af2
5 changed files with 128 additions and 24 deletions

View File

@ -103,7 +103,7 @@
(http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard&p=606865&viewfull=1#post606865).
Before adding a delay we were having [strange problems with ghosting]
(http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard&p=605857&viewfull=1#post605857).
### PWM on ports OC1(A|B|C) (see datasheet section 14.10)

View File

@ -8,6 +8,8 @@
* Timer interface
*
* Prefix: `timer__`
*
* `timer__init()` is meant to be called once, on startup, by `main()`
*/
@ -17,7 +19,29 @@
// ----------------------------------------------------------------------------
// TODO
void timer__init(void);
/** functions/timer__init/description
* Initialize the timer
*/
uint32_t timer__get_milliseconds(void);
/** functions/timer__get_milliseconds/description
* Return the number of milliseconds since the timer was initialized (mod 2^32)
*
* Usage notes:
*
* - It's unnecessary to keep 32-bit (or even 16-bit) resolution when storing
* the value returned by `timer__get_milliseconds()` if you don't need it.
* Casting to a smaller unsigned value should be safe (as long as you cast
* *all* the values you plan to compare with each other to the same type!).
*
* - Use `end_time - start_time` for determining time difference. Since the
* returned values are unsigned (and you should be storing them in unsigned
* variables as well) this will work across overflows, for up to the maximum
* amount of milliseconds representable by the type you're using. (See [this
* answer] (http://stackoverflow.com/a/50632) on <http://stackoverflow.com/>
* if you're curious as to why.)
*/
// ----------------------------------------------------------------------------

View File

@ -5,28 +5,11 @@
* ------------------------------------------------------------------------- */
/** description
* Implements the time defined in "../timer.h" for the ATMega32U4
* Implements the timer functions defined in "../timer.h" for the ATMega32U4
*
* Prefix: `timer__`
*
* `timer__init()` is meant to be called once, on startup, by `main()`
*
* See the accompanying '.md' file for more documentation.
*
*
* Usage Notes:
*
* - It's unnecessary to keep 32-bit (or even 16-bit) resolution when storing
* the value returned by `timer__get_milliseconds()` if you don't need it.
* Casting to a smaller unsigned value should be safe (as long as you cast
* *all* the values you plan to compare with each other to the same type!).
*
* - Use `end_time - start_time` for determining time difference. Since the
* returned values are unsigned (and you should be storing them in unsigned
* variables as well) this will work across overflows, for up to the maximum
* amount of milliseconds representable by the type you're using. (See [this
* answer] (http://stackoverflow.com/a/50632) on <http://stackoverflow.com/>
* if you're curious as to why.)
* See the accompanying '.md' file for documentation.
*/
@ -52,7 +35,6 @@ uint32_t timer__get_milliseconds(void) {
// ----------------------------------------------------------------------------
// TODO: document this in the '.md' file too
ISR(TIMER0_COMPA_vect) {
_milliseconds++;
}

View File

@ -0,0 +1,85 @@
## 8-bit Timer/Counter Register Description (see datasheet section 13.8)
TCCR0A : Timer/Counter Control Register A
.---------------------------------------------------------------.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---------------------------------------------------------------|
| COM0A | COM0A | COM0B | COM0B | Reserved | WGM1 | WGM0 |
'---------------------------------------------------------------'
TCCR0B : Timer/Counter Control Register B
.---------------------------------------------------------------.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---------------------------------------------------------------|
| FOC0A | FOC0B | Reserved | WGM02 | CS02 | CS01 | CS00 |
'---------------------------------------------------------------'
* We want:
* `COM0A` = `0b10` : Clear `OC0A` on Compare Match
* `COM0B` = `0b00` : Normal port operation, `OC0B` disconnected
* `WGM` = `0b010` : CTC (see section 13.6.2 "Clear Timer on Compare
Match (CTC) Mode")
* `CS` = `0b011` : clk_i/o / 64 (from prescaler)
TIMSK0 : Timer/Counter Interrupt Mask Register
.-----------------------------------------------------------------.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|-----------------------------------------------------------------|
| Reserved | OCIE0B | OCIE0A | TOIE0 |
'-----------------------------------------------------------------'
* We want:
* `OCIE0A` = `0b1` : enable the Timer/Counter0 Compare Match A
interrupt
* We also want to set `OCR0A` (Output Compare Register A) to `250`
* Since we're using CTC mode with `OCIE0A` enabled, we will be using the
`TIMER0_COMPA_vect` interrupt vector (see
[the avr-libc documentation on interrupts]
(http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html)).
## Other Notes
* References:
* [Newbie's Guide to AVR Timers]
(http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106)
: tutorial lby Deana Camera
* For a CPU frequency of 16 MHz:
--------------------------------------------
prescale value ticks per millisecond
---------------- -----------------------
1 16000
8 2000
64 250
256 62.5
1024 15.625
--------------------------------------------
* So if we set the prescaler to 64, we can just barely get to a millisecond
within the range of an 8-bit counter (2^8-1 = 255, and we need 250
ticks).
* Abbreviations:
* `COM`: Compare
* `CS`: Clock Select
* `FOC`: Force Output Compare
* `TCCR: Timer/Counter Control Register
* `TIMSK`: Timer/Counter Interrupt Mask Register
* `WGM`: Waveform Generation Module
-------------------------------------------------------------------------------
Copyright &copy; 2013 Ben Blazak <benblazak.dev@gmail.com>
Released under The MIT License (see "doc/licenses/MIT.md")
Project located at <https://github.com/benblazak/ergodox-firmware>

View File

@ -13,6 +13,7 @@
#include <stdint.h>
#include <util/delay.h>
#include "../firmware/keyboard.h"
#include "../firmware/lib/timer.h"
#include "../firmware/lib/usb.h"
#include "./main.h"
@ -65,7 +66,9 @@ int main(void) {
static bool key_is_pressed;
static bool key_was_pressed;
kb__init(); // initialize hardware (besides USB)
static uint8_t time_scan_started;
kb__init(); // initialize hardware (besides USB and timer)
kb__led__state__power_on();
@ -73,13 +76,24 @@ int main(void) {
while (!usb__is_configured());
kb__led__delay__usb_init(); // give the OS time to load drivers, etc.
timer__init();
kb__led__state__ready();
time_scan_started // first iteration, scan immediately
= (uint8_t)timer__get_milliseconds() - OPT__DEBOUNCE_TIME;
for(;;) {
temp = is_pressed;
is_pressed = was_pressed;
was_pressed = temp;
// delay if necessary, then rescan
// - add 1 to `OPT__DEBOUNCE_TIME` in case `time_scan_started` caught
// the tail end of the millisecond it recorded
while( (uint8_t)timer__get_milliseconds() - time_scan_started
< OPT__DEBOUNCE_TIME + 1 );
time_scan_started = timer__get_milliseconds();
kb__update_matrix(*is_pressed);
// "execute" keys that have changed state
@ -94,7 +108,6 @@ int main(void) {
}
usb__kb__send_report(); // (even if nothing's changed)
_delay_ms(OPT__DEBOUNCE_TIME);
// note: only use the `kb__led__logical...` functions here, since the
// meaning of the physical LEDs should be controlled by the layout