Model 2: The Abakus Clock¶
- Date:
2017-08-19
Design Decisions¶
32 ticks/sec, generated from main crystal (11.0592 MHz)
timeup clock with simple counters, no structures, no timezone
optional: uptime counter
optional: led.1 blinking 1/sec
multitasker
new: a battery backed real time clock is connected via i2c
new: start time is read from RTC
new: shift register drives LEDs as display
Description¶
The code included below is a complete, working example, tested on an
atmega644p controller. The syntax for the includes is such that
amforth-shell.py will upload the programm and resolve all
#include file directives.
This clock is derived from the Minimal Clock by adding a geek display (Abakus Display) and a battery backed RTC.
I2C RTC (PCF8583)¶
#include i2c_rtc_pcf8583.fs
Abakus Display¶
Obviously, we need to define the pin connected to the shift register, and load the words to transfer data to the shift register(s)
\ abakus display
PORTD 2 portpin: sr_latch
PORTD 3 portpin: sr_clock
PORTD 4 portpin: sr_data
#include shiftregister.fs
Controller Board and display¶
Prototype Display handrouted :-)¶
The Code¶
1\ 2017-08-16 main-02-abakus.fs
2\ Author: Erich Wälde
3\ License: this code is explizitly placed in the public domain
4\
5\ include syntax for upload with amforth-shell.py
6\
7\ 11.059200 MHz main crystal
8\ timer/counter1
9\ 32 ticks/second
10\
11\ minimal clock
12\ plus i2c, i2c RTC (pcf8583)
13\ display: shift registers (74x595) and LEDs
14\
15#include builds.frt
16#include erase.frt
17#include dot-base.frt
18#include imove.frt
19#include bitnames.frt
20#include marker.frt
21#include environment-q.frt
22#include dot-res.frt
23#include avr-values.frt
24#include is.frt
25#include dumper.frt
26#include interrupts.frt
27\ these definitions are resolved by amforth-shell.py as needed
28\ include atmega644p.fs
29
30#include flags.frt
31#include 2variable.frt
32#include 2constant.frt
33#include 2-fetch.frt
34#include 2-store.frt
35#include m-star-slash.frt
36#include quotations.frt
37#include avr-defers.frt
38#include defers.frt
39
40marker --start--
41
42\ --- ports, pins, masks
43
44PORTB 2 portpin: led.0
45PORTB 3 portpin: led.1
46PORTB 4 portpin: led.2
47PORTB 5 portpin: led.3
48
49PORTC 0 portpin: i2c_scl
50PORTC 1 portpin: i2c_sda
51
52\ abakus display
53PORTD 2 portpin: sr_latch
54PORTD 3 portpin: sr_clock
55PORTD 4 portpin: sr_data
56
57\ --- famous includes and other words
58: ms ( n -- ) 0 ?do pause 1ms loop ;
59: u0.r ( u n -- ) >r 0 <# r> 0 ?do # loop #> type ;
60: odd? ( x -- t/f ) $0001 and 0= 0= ;
61: even? ( x -- t/f ) $0001 and 0= ;
62
63\ --- driver: status leds
64#include leds.fs
65
66\ --- driver: i2c rtc clock
67: bcd>dec ( n.bcd -- n.dec )
68 $10 /mod #10 * + ;
69: dec>bcd ( n.dec -- n.bcd )
70 #100 mod #10 /mod $10 * + ;
71
72#include i2c-twi-master.frt
73#include i2c.frt
74#include i2c-detect.frt
75: +i2c ( -- )
76 i2c_scl pin_pullup_on
77 i2c_sda pin_pullup_on
78 0 \ prescaler
79 #6 \ bit rate --- 400kHz @ 11.0592 MHz
80 i2c.init
81;
82
83: i2c.scan
84 base @ hex
85 $79 $7 do
86 i i2c.ping? if i 3 .r then
87 loop
88 base !
89 cr
90;
91$50 constant i2c_addr_rtc
92#include i2c_rtc_pcf8583.fs
93
94
95\ --- master clock
96\ --- timeup
97#include timeup_v0.0.fs
98 \ tu.counts -- fields available as:
99 \ tick sec min hour day month year
100 \ last_day_of_month ( year month -- last_day )
101 \ timeup.init
102 \ timeup
103 \ tu.upd.limits ( Y m -- )
104
105\ --- uptime
1062variable uptime
107: .uptime ( -- ) uptime 2@ decimal ud. [char] s emit ;
108: ++uptime ( -- ) 1. uptime 2@ d+ uptime 2! ;
109
110\ --- timer1 clock tick
111\ 32 ticks/sec
112\ timer_1_ overflow
113\ clock source main crystal/256
114#include clock_tick1_main.fs
115 \ +ticks
116 \ tick.over? ( -- t/f )
117 \ tick.over!
118 \ half.second.over? ( -- 0|1|2 )
119: clock.set ( Y m d H M S -- )
120 sec ! min ! hour !
121 1- day !
122 over over
123 1- month ! year !
124 ( Y m ) tu.upd.limits
125;
126: clock.get ( -- S M H d m Y )
127 sec @ min @ hour @
128 day @ 1+ month @ 1+ year @
129;
130: clock.dot ( S M H d m Y -- )
131 #4 u0.r [char] - emit #2 u0.r [char] - emit #2 u0.r [char] _ emit
132 #2 u0.r [char] : emit #2 u0.r [char] : emit #2 u0.r
133;
134: clock.show ( -- )
135 clock.get
136 clock.dot
137;
138
139: .date
140 year @ 4 u0.r
141 month @ 1+ 2 u0.r
142 day @ 1+ 2 u0.r
143;
144: .time
145 hour @ 2 u0.r [char] : emit
146 min @ 2 u0.r [char] : emit
147 sec @ 2 u0.r
148;
149
150: hwclock>clock ( -- )
151 rtc.get \ --
152 year !
153 1- month !
154 1- day !
155 hour !
156 min !
157 sec !
158 drop \ 1/100 secs
159 year @ month @ 1+ tu.upd.limits
160;
161: clock>hwclock ( -- )
162 year @ month @ 1+ day @ 1+
163 hour @ min @ sec @
164 tick @ #100 ticks/sec m*/
165 ( Y m d H M S S/100 ) rtc.set
166;
167
168#include shiftregister.fs
169#include abakus.fs
170: clock.display.abakus.time ( -- )
171 hour @ #10 /mod swap
172 min @ #10 /mod swap
173 sec @ #10 /mod swap
174 6 type.abakus
175;
176
177\ --- multitasker
178#include multitask.frt
179: +tasks multi ;
180: -tasks single ;
181
182
183\ --- timeup jobs ---------------------------
184: job.tick
185;
186: job.sec
187 ++uptime
188 clock.display.abakus.time
189;
190: job.min
191;
192: job.hour ;
193: job.day ;
194: job.month
195 \ update length of month in tu.limits
196 year @ month @ 1+ tu.upd.limits
197;
198: job.year
199 \ update YYYY in eeprom of rtc
200 \ year @ rtc.set.year
201;
202
203create Jobs
204 ' job.tick ,
205 ' job.sec , ' job.min , ' job.hour ,
206 ' job.day , ' job.month , ' job.year ,
207
208variable jobCount
209: jobCount++
210 jobCount @
211 6 < if
212 1 jobCount +!
213 then
214;
215
216\ --- task 2 --------------------------------
217: run-masterclock
218 ['] tx-poll to emit \ add emit to run-masterclock
219 begin
220
221 tick.over? if
222 tick.over!
223 1 tick +!
224 job.tick
225 then
226
227 half.second.over?
228 dup 0<> if
229 dup odd? if \ half second
230 led.1 off
231 else \ second
232 led.1 on
233 timeup
234 0 tick !
235 1 jobCount !
236 then
237 then
238 drop
239
240 \ run one job per loop, not all at once
241 jobCount @
242 bv tu.flags fset?
243 if
244 jobCount @ dup
245 Jobs + @i execute
246 bv tu.flags fclr
247 then
248 jobCount++
249
250 pause
251 again
252;
253$40 $40 0 task: task-masterclock \ create task space
254: start-masterclock
255 task-masterclock tib>tcb
256 activate
257 \ words after this line are run in new task
258 run-masterclock
259;
260: starttasker
261 task-masterclock task-init \ create TCB in RAM
262 start-masterclock \ activate tasks job
263
264 onlytask \ make cmd loop task-1
265 task-masterclock tib>tcb alsotask \ start task-2
266 multi \ activate multitasking
267;
268
269\ --- main ----------------------------------
270: init
271 +leds leds-intro
272 #2017 1 1 0 0 0 clock.set
273 0. uptime 2!
274 +ticks
275 timeup.init
276 +i2c
277 i2c_addr_rtc i2c.ping? if
278 hwclock>clock
279 else
280 #2017 1 1 0 0 0 clock.set
281 then
282 +sr
283;
284: run
285 init
286 starttasker
287;
288: run-turnkey
289 applturnkey
290 init
291 starttasker
292;
293\ ' run-turnkey to turnkey
294
295: .d ( -- )
296 decimal
297 .uptime space space
298 clock.show space
299 tick @ . space
300 ct.ticks.follow @ .
301 cr
302;