Model 1: The Fairly Minimal Clock¶
- Date:
2017-08-13
Design Decisions¶
32 ticks/sec, generated from main crystal (11.0592 MHz)
timeup clock with simple counters, no structures, no timezone
display on serial, on demand
.doptional: uptime counter
optional: led.1 blinking 1/sec
fixed start time (2017-01-01 00:00:00)
multitasker
Description¶
The code included below is a complete, working example, tested on an
atmega644p controller. The initial list of includes can be shortened
somewhat, it just makes debugging and working simpler. The syntax for
the includes is such that amforth-shell.py will upload the
programm and resolve all #include file directives.
Model 1 is just living inside this eval board. There is no display other than the serial connection!¶
The pin definitions are directly related to the electronic schematics of your system. For this fairly minimal clock only 4 status LEDs are defined, which may be absent alltogether.
The includes after that correspond to what has been detailed in the Ingredients section before (Ingredients and Clocks).
timeup_v0.0.fs implements the clock counters and function
timeup, which advances all counters of the clock by one second
including counter overflows.
uptime is a variable to count the uptime of the system in
seconds. It is optional, however, it should illustrate using the
periodic jobs to get some work done.
clock_tick1_main.fs implements the clock ticks driven by the
main crystal and generated as timer/counter1 overflow interrupts.
The functions clock.set, clock.get, and clock.show are
there to conveniently set the clock and show date and time. No
timezone has been implemented. The clock will run whatever time is
set.
multitask.frt provides the mechanics to have the clock run in
the background and the command loop still available at the serial
connection.
After all that, the periodic jobs are defined. Only two things are
done: job.sec will increment the uptime counter, and
job.month will update the length of the month in the Limits
array.
The function run-masterclock implements the background job. It
will run as often as possible. It will check, whether a tick is over
and call job.tick if this is the case. It will also check if half
a second or a full second has passed, and light up one LED
accordingly. If a full second has passed, then timeup is called to
advance the clock counters, and jobCount is set, such that in the
rounds through this loop to come, all needed periodic jobs are called,
one job per loop.
run-masterclock is wrapped as a task:, start-masterclock
will start the background task. The function starttasker is
starting all tasks, thereby converting the command loop into a task as
well. Finally the multitasker is activated.
init is to set up everything in working conditions. run will
start the whole show on the command prompt. In order to make the
program start automatically at powerup, run-turnkey is defined and
can be registered as turnkey.
The last function, .d is our display. It is to be called on the
command loop via serial connection. Similarly the clock can be set
now, it should run with an error of a few seconds per day.
> .d
2451 s 2017-01-01_00:40:51 13 12909
ok
> #2017 8 13 18 41 30 clock.set .d
2525 s 2017-08-13_18:41:30 3 15299
ok
> .d
2530 s 2017-08-13_18:41:35 26 15450
ok
>
The Code¶
1\ 2017-08-13 main-01-fairly-minimal.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\ include syntax for upload with amforth-shell.py
15\
16\ 11.059200 MHz main crystal
17\ timer/counter1
18\ 32 ticks/second
19\
20#include builds.frt
21#include erase.frt
22#include dot-base.frt
23#include imove.frt
24#include bitnames.frt
25#include marker.frt
26#include environment-q.frt
27#include dot-res.frt
28#include avr-values.frt
29#include is.frt
30#include dumper.frt
31#include interrupts.frt
32\ these definitions are resolved by amforth-shell.py as needed
33\ include atmega644p.fs
34
35#include flags.frt
36#include 2variable.frt
37#include 2constant.frt
38#include 2-fetch.frt
39#include 2-store.frt
40#include m-star-slash.frt
41#include quotations.frt
42#include avr-defers.frt
43#include defers.frt
44
45marker --start--
46
47\ --- ports, pins, masks
48
49PORTB 2 portpin: led.0
50PORTB 3 portpin: led.1
51PORTB 4 portpin: led.2
52PORTB 5 portpin: led.3
53
54\ --- famous includes and other words
55: ms ( n -- ) 0 ?do pause 1ms loop ;
56: u0.r ( u n -- ) >r 0 <# r> 0 ?do # loop #> type ;
57: odd? ( x -- t/f ) $0001 and 0= 0= ;
58: even? ( x -- t/f ) $0001 and 0= ;
59
60\ --- driver: status leds
61#include leds.fs
62
63\ --- master clock
64\ --- timeup
65#include timeup_v0.0.fs
66 \ tu.counts -- fields available as:
67 \ tick sec min hour day month year
68 \ last_day_of_month ( year month -- last_day )
69 \ timeup.init
70 \ timeup
71 \ tu.upd.limits ( Y m -- )
72
73\ --- uptime
742variable uptime
75: .uptime ( -- ) uptime 2@ decimal ud. [char] s emit ;
76: ++uptime ( -- ) 1. uptime 2@ d+ uptime 2! ;
77
78\ --- timer1 clock tick
79\ 32 ticks/sec
80\ timer_1_ overflow
81\ clock source main crystal/256
82#include clock_tick1_main.fs
83 \ +ticks
84 \ tick.over? ( -- t/f )
85 \ tick.over!
86 \ half.second.over? ( -- 0|1|2 )
87: clock.set ( Y m d H M S -- )
88 sec ! min ! hour !
89 1- day !
90 over over
91 1- month ! year !
92 ( Y m ) tu.upd.limits
93;
94: clock.get ( -- S M H d m Y )
95 sec @ min @ hour @
96 day @ 1+ month @ 1+ year @
97;
98: clock.dot ( S M H d m Y -- )
99 #4 u0.r [char] - emit #2 u0.r [char] - emit #2 u0.r [char] _ emit
100 #2 u0.r [char] : emit #2 u0.r [char] : emit #2 u0.r
101;
102: clock.show ( -- )
103 clock.get
104 clock.dot
105;
106\ --- multitasker
107#include multitask.frt
108 \ activate ( tid -- )
109 \ task-sleep ( tid -- )
110 \ task-awake ( tid -- )
111 \ task: ( rs-size ds-size -- tid )
112 \ onlytask ( -- )
113 \ alsotask ( tid -- )
114 \ single ( -- )
115 \ multi ( -- )
116 \ tasks ( -- )
117: +tasks multi ;
118: -tasks single ;
119
120
121\ --- timeup jobs ---------------------------
122: job.tick
123;
124: job.sec
125 ++uptime
126;
127: job.min
128;
129: job.hour ;
130: job.day ;
131: job.month
132 \ update length of month in tu.limits
133 year @ month @ 1+ tu.upd.limits
134;
135: job.year ;
136
137create Jobs
138 ' job.tick ,
139 ' job.sec , ' job.min , ' job.hour ,
140 ' job.day , ' job.month , ' job.year ,
141
142variable jobCount
143: jobCount++
144 jobCount @
145 6 < if
146 1 jobCount +!
147 then
148;
149
150\ --- task 2 --------------------------------
151: run-masterclock
152 ['] tx-poll to emit \ add emit to run-masterclock
153 begin
154
155 tick.over? if
156 tick.over!
157 1 tick +!
158 job.tick
159 then
160
161 half.second.over?
162 dup 0<> if
163 dup odd? if \ half second
164 led.1 off
165 else \ second
166 led.1 on
167 timeup
168 0 tick !
169 1 jobCount !
170 then
171 then
172 drop
173
174 \ run one job per loop, not all at once
175 jobCount @
176 bv tu.flags fset?
177 if
178 jobCount @ dup
179 Jobs + @i execute
180 bv tu.flags fclr
181 then
182 jobCount++
183
184 pause
185 again
186;
187$40 $40 0 task: task-masterclock \ create task space
188: start-masterclock
189 task-masterclock tib>tcb
190 activate
191 \ words after this line are run in new task
192 run-masterclock
193;
194: starttasker
195 task-masterclock task-init \ create TCB in RAM
196 start-masterclock \ activate tasks job
197
198 onlytask \ make cmd loop task-1
199 task-masterclock tib>tcb alsotask \ start task-2
200 multi \ activate multitasking
201;
202
203\ --- main ----------------------------------
204: init
205 +leds leds-intro
206 #2017 1 1 0 0 0 clock.set
207 0. uptime 2!
208 +ticks
209 timeup.init
210 \ cd.localtime
211;
212: run
213 init
214 starttasker
215;
216: run-turnkey
217 applturnkey
218 init
219 starttasker
220;
221\ ' run-turnkey to turnkey
222
223: .d ( -- )
224 decimal
225 .uptime space space
226 clock.show space
227 tick @ . space
228 ct.ticks.follow @ .
229 cr
230;