Generating Ticks from an additional clock crystal¶
- Date:
 2017-08-07
Intro¶
Our favorite microcontroller features two pins to use an external clock crystal at 32768 Hz to drive timer/counter2. We use its overflows to generate ticks, moreover we could put the microcontroller to sleep between these events, if needed.
Design Decisions¶
Timer/counter2 is driven asynchronouosly at 32768 Hz
Timer/counter2 is an 8-bit counter, counting 256 cycles unless instructed otherwise
So we get
128ticks/second:32768/256 = 128prescaler offers dividers of 8, 32, 64, 128, 256, 1024; with these values we could also generate 16, 4, 2 , 1, 1/2, 1/4 ticks/second.
in addition we could set CTC mode (clear counter on compare match) and choose the compare value. So for example setting the prescaler to
8and the compare match value to128-1we should get32ticks/second again.
Setting up Timer2 for asynchronous operation¶
We set up timer/counter2 in normal mode, it will count 256 clock
cycles and then issue an overflow interrupt. Then we switch the clock
source to the external clock crystal via asynchronuos mode.
: +ticks
  ...
  [ %00000000                 \ normal mode
  ] literal TCCR2A c!
  [ %00000001                 \ 001 = clock_ts2, prescaler 1
  ] literal TCCR2B c!
  ASSR_AS2 ASSR  c!           \ clock source: 32 kiHz crystal
  ...
;
TODO: add toggling an output pin for debug!
Serving Timer2 overflow interrupts¶
Similar to the code explained in the section
Generating Ticks from the main crystal, the ISR increments variable
ct.ticks. The main loop will acknowledge the effect by
incrementing ct.ticks.follow.
\ timer overflow ISR
: tick2_isr ( -- )  1 ct.ticks +! ;
: +ticks    ( -- )
  ...
  ['] tick2_isr TIMER2_OVFAddr int!
  TIMSK2 c@ $01 or TIMSK2 c!  \  enable OVF2 interupt
;
variable ct.ticks
variable ct.ticks.follow
: tick.over? ( -- t/f ) ct.ticks.follow @  ct.ticks @  - 0< ;
: tick.over! ( -- )     1 ct.ticks.follow +! ;
Putting it all together¶
We should find the above code snippets used in the main program somehow like this:
include ewlib/clockticks_clock_crystal.fs
variable ticks
: init
  ...
  0 ticks !
  +ticks
;
: run-loop
  init
  begin
    tick.over? if
      tick.over!
      \ one tick over, do someting
      1 ticks +!    \ count ticks
    then
    second.over? > if
      ticks @ ticks/sec - ticks !
      \ one second over, do something!
      ...
    then
  again
;
The Code¶
 1\ 2017-03-27 EW   ewlib/clock_tick2_clockcrystal.fs
 2\
 3\ Written in 2017 by Erich Wälde <erich.waelde@forth-ev.de>
 4\
 5\ To the extent possible under law, the author(s) have dedicated
 6\ all copyright and related and neighboring rights to this software
 7\ to the public domain worldwide. This software is distributed
 8\ without any warranty.
 9\
10\ You should have received a copy of the CC0 Public Domain
11\ Dedication along with this software. If not, see
12\ <http://creativecommons.org/publicdomain/zero/1.0/>.
13\
14
15#128 constant ticks/sec
16variable ct.ticks
17variable ct.ticks.follow
18variable last.tick[6]
19variable last.tick[7]
20
21
22\ timer 2 overflow interrupt service routine
23: tick2_isr
24  1 ct.ticks +!
25;
26
27: tick.over? ( -- t/f ) ct.ticks.follow @  ct.ticks @  - 0< ;
28: tick.over! ( -- )     1 ct.ticks.follow +! ;
29
30
31\ enable ticks
32\ crystal:   32768 /sec
33\ clock src: 32768 /sec
34\ overflow:  32768/256 = 128 /sec
35: +ticks
36  0 ct.ticks         !
37  0 ct.ticks.follow  !
38  0 last.tick[6]     !
39  0 last.tick[7]     !
40
41  \ --- timer2 ---
42  [ %00000000                   \ normal mode
43  ] literal TCCR2A c!
44  [ %00000001                   \ 001 = clock_ts2
45  ] literal TCCR2B c!
46  ASSR_AS2 ASSR  c!             \ source: 32 kiHz crystal
47  ['] tick2_isr TIMER2_OVFAddr int! \ register ISR
48  TIMSK2 c@ $01 or TIMSK2 c!    \  enable OVF2 interupt
49;
50
51\ disable ticks
52: -ticks
53  TIMSK2 c@
54  [ $01 invert ] literal
55  and TIMSK2  c! ( clr Timer 2 )
56  $00  ASSR   c!
57  $00  TCCR2B c!
58  $07  TIFR2  c! \ clear interrupt flags, jibc
59;
60
61
62\ one second == 128 ticks
63\ half second == 64 ticks
64\ that is a toggle on bit 6 of ct.ticks.follow
65: half.second.over? ( -- 0|1|2 )
66  \ return: 0 == false
67  \         1 == half second over
68  \         2 == second over
69  ct.ticks.follow c@
70  $0040 and 0= 0=  \ extract significant bit as t/f
71  dup last.tick[6] @ = if
72    \ no change, done
73    drop 0
74  else
75    dup 0= if
76      \ falling edge, second over
77      2
78    else
79      \ rising edge, half second over
80      1
81    then
82    swap
83    ( sig.bit-t/f ) last.tick[6] !
84  then
85;
86
87: second.over? ( -- t/f )
88  ct.ticks.follow c@  $0080 and 0= 0=
89  dup  last.tick[7] @  = if
90    drop 0
91  else
92    last.tick[7] !
93    -1
94  then
95;