fl { RTC DS1337 driver PropForth 5.5 2013/06/01 16:27:20 RTC DS1337 Propeller scl ---- P28 0x1c sda ---- P29 0x1d } wvariable err \ Slave addres for DS1337 hD0 wconstant slave \ register name 0 wconstant current 7 wconstant alarm1 hB wconstant alarm2 hE wconstant control hF wconstant status \ register value h40 wconstant 12Hour h20 wconstant AM/PM h40 wconstant DY/DT h80 wconstant OSC 4 wconstant INTCON h80 wconstant OSC \ SQW_rate 0 wconstant 1Hz \ 1Hz 1 wconstant 4kHz \ 4.096kHz 2 wconstant 8kHz \ 8.192kHz 3 wconstant 32kHz \ 32.68kHz \ Convert week-number to string \ rtc_week ( n1 -- ) n1:1 to 7 : rtc_week 7 and c" MONTUEWEDTHUFRISATSUN" 1+ swap 1 max 1- 3 u* + 3 0 do dup C@ emit 1+ loop drop ; \ Convert month-number to string \ rtc_mon ( n1 -- ) n1:1 to 12 : rtc_mon c" JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC" 1+ swap hC min 1 max 1- 3 u* + 3 0 do dup C@ emit 1+ loop drop ; \ bcd> ( n1 -- n2 ) convert bcd byte n1 to hex byte n2 [ifndef bcd> : bcd> dup hF and swap hF0 and 1 rshift dup 2 rshift + + ; ] \ \ >bcd ( n1 -- n2 ) convert hex byte n1 to bcd byte n2 [ifndef >bcd : >bcd d10 u/mod 4 lshift + ; ] \ _rtcflip7 ( n7 n6 n5 n4 n3 n2 n1 -- n1 n2 n3 n4 n5 n6 n7 ) flip the top 7 items on the stack : _rtcflip7 rot >r rot >r rot >r rot >r rot >r swap r> r> r> r> r> rot >r rot >r rot >r swap r> r> r> swap rot ; \ error message \ ( -- ) : err_msg ." I2C error" cr ; \ Write data \ ( n1 -- n2 ) n1:data n2:t/f true=success \ Write 1byte, then receive 1bit(ACK:Hi NACK:Lo) : DS1337_w _eewrite if 0 else 1 then ; \ Read data from DS1337-register \ ( n1 -- n2 ) n1:register n2:data : rd_reg \ Start I2C for DS1337 _eestart \ Write slave address[wr] slave DS1337_w if \ Write register-addr n1 DS1337_w if \ Set read_process _eestart slave 1 or DS1337_w if \ Read 1byte ,then set sda to Hi(NACK:master->slave) -1 _eeread \ Stop I2C _eestop else err_msg then else err_msg then else err_msg then ; \ Read data to DS1337-register \ ( n1 n2 -- ) n1:data n2:register : wr_reg 0 err W! \ Start I2C for DS1337 _eestart \ Write slave address[wr] slave DS1337_w if \ Write register-addr n2 DS1337_w if \ Write n1 DS1337_w 1 <> if 1 err W! then err W@ if err_msg else \ Stop I2C _eestop then else 3drop 3drop drop err_msg then else 3drop 3drop drop err_msg then ; \ Set SQW \ ( n1 --) n1:1Hz or 4kHz or 8kHz or 32kHz (default:32.768kHz) : set_SQW control rd_reg hE7 and swap 3 lshift or control wr_reg ; \ Write IE for alarm1/alarm2 \ ( n1 n2 -- ) n2:0(disable)/1(enable) n1:alarm1 or alarm2 : alm_Int alarm1 = \ Check alarm1 or alarm2 if 2 else 1 then dup >r \ Push A2IE or A1IE control rd_reg \ Read CONTROL >r \ Push CONTROL hFC or r> and \ Pop CONTROL, then mask swap if r> \ Pop A2IE or A1IE 2 = if 1 else 2 then or \ Add alarm*InterruptEnable bit else r> drop \ Pop alm*_IE and drop then control wr_reg \ Write CONTROL ; \ Set/Clear INTCN bit \ ( n1 -- ) n1:0/1 0=clear 1=set : set_INTCN control rd_reg hFB and swap if 4 or then control wr_reg ; \ Erase alarm1/alarm2 Interupt-flag \ ( n1 -- ) n1:alarm1/alarm2 : erase_alm alarm1 = if hFE else hFD then status wr_reg ; \ Print 1digit \ ( n1 -- ) n1:digit (0-9) : 1digit tochar emit ; \ Alignment/Print time-digit to 2digits \ ( n1 -- ) n1:time-digit (0-24,0-59) : 2digit dup d10 < if \ If n1 < d10 0 tochar emit tochar emit else \ If n1 > 9 d10 u/mod tochar emit tochar emit then ; \ --------------- Current time ------------------------------------------------ \ Read/Convert all time-data from DS1337 \ ( -- n1 n2 n3 n4 n5 n6 n7 ) \ n1 - second (00 - 59) \ n2 - minute (00 - 59) \ n3 - hour (00 - 23) \ n4 - day of week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) \ n5 - date (01 - 31) \ n6 - month (01 - 12) \ n7 - yesr (2000 - 2099) : rd_current 7 0 do current i + rd_reg bcd> loop cr ." CurrentTime setting" cr ." Year: " d2000 + . cr ." Date: " rtc_mon space . rtc_week cr ." Time: " >bcd dup 12Hour and 0<> if \ 12Hour-mode dup AM/PM and swap \ Check AM/PM h1F and bcd> swap \ Convert Hour to hex byte if ." PM" else ." AM" then \ Print AM or PM space else bcd> then 2digit h3A emit 2digit h3A emit 2digit cr cr ; \ Set current-time to DS1337 (second=0) \ ( n1 n2 n3 n4 n5 n6 -- ) \ n1 - yesr (00 - 99) \ n2 - month (01 - 12) \ n3 - date (01 - 31) \ n4 - day-of-week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) \ n4 - hour (00 - 23) \ n5 - minute (00 - 59) : set_current 0 status wr_reg \ Clear OSF >bcd >r \ minute >bcd >r \ hour >r \ day-of-week >bcd >r \ day >bcd >r \ month d2000 - >bcd \ year r> r> r> r> r> 0 7 0 do current i + wr_reg loop rd_current ; \ --------------- Alarm ------------------------------------------------ \ Set DY/DT-mode on alarm1 and alarm2 \ If changed DY/DT-mode, value for Day/Date-mode must be reinitialized \ ( n1 n2 -- ) n1:1=Day 0=Date n1:alarm1 or alarm2 : wr_day_alm alarm1 = if alarm1 3 + else alarm2 2+ then tuck rd_reg swap if DY/DT or \ Set bit[DY/DT] else DY/DT invert and \ Clear bit[DY/DT] then swap wr_reg ; \ Check DY/DT-mode on alarm2 \ ( n1 -- n2 ) n1:alarm1 or alarm2 n2:1=Day 0=Date : day_alm? alarm1 = if alarm1 3 + else alarm2 2+ then rd_reg DY/DT and if 1 else 0 then ; \ --------------- Alarm1 time ------------------------------------------------ \ Read/Convert all alarm1-data from DS1337 \ ( -- n1 n2 n3 n4 ) \ n1 - second (00 - 59) \ n2 - minute (00 - 59) \ n3 - hour (00 - 23) \ n4 - day of week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) \ date (1-31) : rd_alm1 4 0 do alarm1 i + rd_reg bcd> loop cr ." Alarm1 setting" cr alarm1 day_alm? if ." Week: " rtc_week else ." Date: " . then cr ." Time: " >bcd dup 12Hour and 0<> if \ 12Hour-mode dup AM/PM and swap \ Check AM/PM h1F and bcd> swap \ Convert Hour to hex byte if ." PM" else ." AM" then \ Print AM or PM space else bcd> then 2digit h3A emit 2digit h3A emit 2digit cr cr ; \ Set alarm1-time to DS1337 (second=0) \ ( n1 n2 n3 -- ) \ n1 - date (01 - 31) bit[DY/DT]=0 \ n1 - day-of-week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) bit[DY/DT]=1 \ n2 - hour (00 - 23) \ n3 - minute (00 - 59) : set_alm1 >bcd >r \ minute >bcd >r \ hour >bcd >r \ day / day-of-week r> r> r> 0 3 0 do alarm1 i + wr_reg loop alarm1 3 + rd_reg DY/DT and or alarm1 3 + wr_reg rd_alm1 ; \ --------------- Alarm2 time ------------------------------------------------ \ Read/Convert all alarm1-data from DS1337 \ ( -- n1 n2 n3 ) \ n1 - minute (00 - 59) \ n2 - hour (00 - 23) \ n3 - day of week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) \ date : rd_alm2 3 0 do alarm2 i + rd_reg bcd> loop cr ." Alarm2 setting" cr alarm2 day_alm? if ." Week: " rtc_week else ." Date: " . then cr ." Time: " >bcd dup 12Hour and 0<> if \ 12Hour-mode dup AM/PM and swap \ Check AM/PM h1F and bcd> swap \ Convert Hour to hex byte if ." PM" else ." AM" then \ Print AM or PM space else bcd> then 2digit h3A emit 2digit cr cr ; \ Set alarm1-time to DS1337 \ ( n1 n2 n3 -- ) \ n1 - date (01 - 31) bit[DY/DT]=0 \ n1 - day-of-week (Mon:1 Tue:2 Wed:3 Thur:4 Fri:5 Sat:6 San:7) bit[DY/DT]=1 \ n2 - hour (00 - 23) \ n3 - minute (00 - 59) : set_alm2 >bcd >r \ minute >bcd >r \ hour >bcd >r \ day / day-of-week r> r> r> 2 0 do alarm2 i + wr_reg loop alarm2 2+ rd_reg DY/DT and or alarm2 2+ wr_reg rd_alm2 ; \ Set 12/24-mode to current/alarm1/alarm2 \ ( n1 n2 -- ) n1:1=12Hour or 0=24Hour n2:register[current or alarm1 or alarm2] : set_12/24 dup >r \ Push register dup alarm2 = if 1+ else 2+ then \ Get regiter address 2dup rd_reg \ Read register(12/24 bit) 12Hour and 6 rshift <> if dup rd_reg dup 12Hour and 0 = if \ Change 24Hour to 12Hour bcd> dup d12 > if d12 - 1 else 0 then \ If hour > 12, subtract d12, then set [AM/PM] 5 lshift swap >bcd or 12Hour or \ Add bit6(12Hour) +bit5(PM/AM) + Hour(bit4-bit0) else \ Change 12Hour to 24Hour dup AM/PM and 0= if 0 else 1 then \ Check if AM/PM swap h1F and bcd> swap if d12 + then \ Add d12 if PM >bcd then over wr_reg then r> \ Pop register current over = if rd_current else alarm1 over = if rd_alm1 else rd_alm2 thens 3drop ; \ --- Use osc when external clock ---------------------------------------- \ Start/Stop OSC \ (n1 -- ) n1:0(stop)/1(start) : osc_on/off dup status rd_reg OSC and st? 7 rshift = if if \ Start OSC ." OSC started." control rd_reg OSC invert and control wr_reg \ Clear OSF-bit d500 delms \ wait status rd_reg OSC invert and status wr_reg else \ Stop OSC ." OSC stopped." control rd_reg OSC or control wr_reg then else if ." OSC already is starting." else ." OSC already stop." then then cr ;