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.

../../_images/i_abakus_display.jpg

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
../../_images/i_model2_1.jpg

Controller Board and display

../../_images/i_model2_3.jpg

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;