1 \ -*- coding: utf-8 -*-
3 \ ==============================================================================
4 \ routines RTC for MSP430FRxxxx
5 \ your target must have a LF_XTAL 32768Hz
6 \ ==============================================================================
8 \ to see kernel options, download FastForthSpecs.f
9 \ FastForth kernel minimal addons: MSP430ASSEMBLER, CONDCOMP
11 \ TARGET SELECTION ( = the name of \INC\target.pat file without the extension)
12 \ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989
13 \ MSP_EXP430FR4133 CHIPSTICK_FR2433 MSP_EXP430FR2433 MSP_EXP430FR2355
16 \ from scite editor : copy your target selection in (shift+F8) parameter 1:
18 \ or, from windows explorer:
19 \ drag and drop this file onto SendSourceFileToTarget.bat
20 \ then select your TARGET when asked.
22 \ ASSEMBLER REGISTERS USAGE
23 \ R4 to R7 must be saved before use and restored after
24 \ scratch registers Y to S are free for use
25 \ under interrupt, IP is free for use
27 \ PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC
28 \ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
30 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
32 \ POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
33 \ POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
35 \ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack
38 \ FORTH conditionnals: unary{ 0= 0< 0> }, binary{ = < > U< }
40 \ ASSEMBLER conditionnal usage with IF UNTIL WHILE S< S>= U< U>= 0= 0<> 0>=
41 \ ASSEMBLER conditionnal usage with ?JMP ?GOTO S< S>= U< U>= 0= 0<> 0<
50 0<> IF MOV #0,TOS THEN \ if TOS <> 0 (FIXPOINT input), set TOS = 0
53 SUB #308,TOS \ FastForth V3.8
55 $0D EMIT \ return to column 1 without CR
56 ABORT" FastForth V3.8 please!"
57 ABORT" target without LF_XTAL !"
58 PWR_STATE \ if no abort remove this word
63 ; --------------------
65 ; --------------------
68 \ to set date, type : d m y DATE!
69 \ to view date, type DATE?
70 \ to set time, type : h m s TIME!, or h m TIME!
71 \ to view time, type TIME?
73 [DEFINED] {RTC} [IF] {RTC} [THEN]
75 MARKER {RTC} \ restore the state before MARKER definition
76 \ {RTC}+8 = BODY+4 = RET_ADR: MARKER_DOES does a call to RET_ADR by default
77 8 ALLOT \ make room for:
78 \ {RTC}+10 for content of previous RTC_VEC
79 \ {RTC}+12 for content of previous COLD_PFA
80 \ {RTC}+14 for content of previous WARM_PFA
81 \ {RTC}+16 for content of previous SLEEP_PFA
85 \ https://forth-standard.org/standard/core/OR
86 \ C OR x1 x2 -- x3 logical OR
94 \ https://forth-standard.org/standard/core/CFetch
95 \ C@ c-addr -- char fetch char from memory
103 \ https://forth-standard.org/standard/core/CStore
104 \ C! char c-addr -- store char in memory
106 MOV.B @PSP+,0(TOS) \ 4
113 [UNDEFINED] SWAP [IF]
114 \ https://forth-standard.org/standard/core/SWAP
115 \ SWAP x1 x2 -- x2 x1 swap top two items
124 [UNDEFINED] OVER [IF]
125 \ https://forth-standard.org/standard/core/OVER
126 \ OVER x1 x2 -- x1 x2 x1
128 MOV TOS,-2(PSP) \ 3 -- x1 (x2) x2
129 MOV @PSP,TOS \ 2 -- x1 (x2) x1
130 SUB #2,PSP \ 1 -- x1 x2 x1
135 [UNDEFINED] DUP [IF] \define DUP and DUP?
136 \ https://forth-standard.org/standard/core/DUP
137 \ DUP x -- x x duplicate top of stack
139 BW1 SUB #2,PSP \ 2 push old TOS..
140 MOV TOS,0(PSP) \ 3 ..onto stack
144 \ https://forth-standard.org/standard/core/qDUP
145 \ ?DUP x -- 0 | x x DUP if nonzero
147 CMP #0,TOS \ 2 test for TOS nonzero
153 [UNDEFINED] DROP [IF]
154 \ https://forth-standard.org/standard/core/DROP
155 \ DROP x -- drop top of stack
162 [UNDEFINED] DEPTH [IF]
163 \ https://forth-standard.org/standard/core/DEPTH
164 \ DEPTH -- +n number of items on stack, must leave 0 if stack empty
168 SUB PSP,TOS \ PSP-S0--> TOS
169 RRA TOS \ TOS/2 --> TOS
170 SUB #2,PSP \ post decrement stack...
176 \ https://forth-standard.org/standard/core/toR
177 \ >R x -- R: -- x push to return stack
186 \ https://forth-standard.org/standard/core/Rfrom
187 \ R> -- x R: x -- pop from return stack ; CALL #RFROM performs DOVAR
197 \ https://forth-standard.org/standard/core/OnePlus
198 \ 1+ n1/u1 -- n2/u2 add 1 to TOS
207 SUB @PSP+,TOS \ 2 u2-u1
211 AND #0,TOS \ 1 flag Z = 1
219 \ https://forth-standard.org/standard/core/Equal
220 \ = x1 x2 -- flag test x1=x2
227 XOR #-1,TOS \ 1 flag Z = 1
232 [UNDEFINED] IF [IF] \ define IF THEN
233 \ https://forth-standard.org/standard/core/IF
234 \ IF -- IFadr initialize conditional forward branch
238 MOV &DP,TOS \ -- HERE
239 ADD #4,&DP \ compile one word, reserve one word
240 MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN
241 ADD #2,TOS \ -- HERE+2=IFadr
245 \ https://forth-standard.org/standard/core/THEN
246 \ THEN IFadr -- resolve forward branch
247 CODE THEN \ immediate
248 MOV &DP,0(TOS) \ -- IFadr
254 [UNDEFINED] ELSE [IF]
255 \ https://forth-standard.org/standard/core/ELSE
256 \ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack
257 CODE ELSE \ immediate
258 ADD #4,&DP \ make room to compile two words
261 MOV W,0(TOS) \ HERE+4 ==> [IFadr]
263 MOV W,TOS \ -- ELSEadr
268 [UNDEFINED] DO [IF] \ define DO LOOP +LOOP
269 \ https://forth-standard.org/standard/core/DO
270 \ DO -- DOadr L: -- 0
274 ADD #2,&DP \ make room to compile xdo
275 MOV &DP,TOS \ -- HERE+2
276 MOV #XDO,-2(TOS) \ compile xdo
277 ADD #2,&LEAVEPTR \ -- HERE+2 LEAVEPTR+2
279 MOV #0,0(W) \ -- HERE+2 L-- 0
283 \ https://forth-standard.org/standard/core/LOOP
284 \ LOOP DOadr -- L-- an an-1 .. a1 0
285 CODE LOOP \ immediate
287 BW1 ADD #4,&DP \ make room to compile two words
289 MOV X,-4(W) \ xloop --> HERE
290 MOV TOS,-2(W) \ DOadr --> HERE+2
291 BEGIN \ resolve all "leave" adr
292 MOV &LEAVEPTR,TOS \ -- Adr of top LeaveStack cell
293 SUB #2,&LEAVEPTR \ --
294 MOV @TOS,TOS \ -- first LeaveStack value
295 CMP #0,TOS \ -- = value left by DO ?
297 MOV W,0(TOS) \ move adr after loop as UNLOOP adr
303 \ https://forth-standard.org/standard/core/PlusLOOP
304 \ +LOOP adrs -- L-- an an-1 .. a1 0
307 GOTO BW1 \ goto BW1 LOOP
311 [UNDEFINED] CASE [IF]
312 \ https://forth-standard.org/standard/core/CASE
313 : CASE 0 ; IMMEDIATE \ -- #of-1
315 \ https://forth-standard.org/standard/core/OF
316 : OF \ #of-1 -- orgOF #of
318 >R \ move off the stack in case the control-flow stack is the data stack.
319 POSTPONE OVER POSTPONE = \ copy and test case value
320 POSTPONE IF \ add orig to control flow stack
321 POSTPONE DROP \ discards case value if =
322 R> \ we can bring count back now
325 \ https://forth-standard.org/standard/core/ENDOF
326 : ENDOF \ orgOF #of -- orgENDOF #of
327 >R \ move off the stack in case the control-flow stack is the data stack.
329 R> \ we can bring count back now
332 \ https://forth-standard.org/standard/core/ENDCASE
333 : ENDCASE \ orgENDOF1..orgENDOFn #of --
342 \ https://forth-standard.org/standard/core/Plus
343 \ + n1/u1 n2/u2 -- n3/u3
351 \ https://forth-standard.org/standard/core/Minus
352 \ - n1/u1 n2/u2 -- n3/u3 n3 = n1-n2
354 SUB @PSP+,TOS \ 2 -- n2-n1 ( = -n3)
356 ADD #1,TOS \ 1 -- n3 = -(n2-n1) = n1-n2
361 [UNDEFINED] MAX [IF] \define MAX and MIN
363 CODE MAX \ n1 n2 -- n3 signed maximum
370 CODE MIN \ n1 n2 -- n3 signed minimum
380 \ https://forth-standard.org/standard/core/TwoTimes
381 \ 2* x1 -- x2 arithmetic left shift
388 [UNDEFINED] UM* [IF] \ case of hardware_MPY
389 \ https://forth-standard.org/standard/core/UMTimes
390 \ UM* u1 u2 -- udlo udhi unsigned 16x16->32 mult.
392 MOV @PSP,&MPY \ Load 1st operand for unsigned multiplication
393 BW1 MOV TOS,&OP2 \ Load 2nd operand
394 MOV &RES0,0(PSP) \ low result on stack
395 MOV &RES1,TOS \ high result in TOS
399 \ https://forth-standard.org/standard/core/MTimes
400 \ M* n1 n2 -- dlo dhi signed 16*16->32 multiply
402 MOV @PSP,&MPYS \ Load 1st operand for signed multiplication
407 [UNDEFINED] UM/MOD [IF]
408 \ https://forth-standard.org/standard/core/UMDivMOD
409 \ UM/MOD udlo|udhi u1 -- ur uq unsigned 32/16->r16 q16
412 MOV #MUSMOD,PC \ execute MUSMOD then return to DROP
417 \ U*/ u1 u2 u3 -- uq u1*u2/u3
419 >R UM* R> UM/MOD SWAP DROP
423 [UNDEFINED] U/MOD [IF]
424 \ U/MOD u1 u2 -- ur uq unsigned division
430 [UNDEFINED] UMOD [IF]
431 \ UMOD u1 u2 -- ur unsigned division
438 \ https://forth-standard.org/standard/core/Div
439 \ U/ u1 u2 -- uq signed quotient
445 [UNDEFINED] SPACES [IF]
446 \ https://forth-standard.org/standard/core/SPACES
447 \ SPACES n -- output n spaces
461 MOV @PSP+,TOS \ -- drop n
466 [UNDEFINED] HERE [IF]
473 : U.R \ u n -- display u unsigned in n width (n >= 2)
475 R> OVER - 0 MAX SPACES TYPE
479 $81EF DEVICEID @ U< ; search device ID: MSP430FR4133 or...
480 DEVICEID @ $8241 U< ; ...MSP430FR2433
482 $830B DEVICEID @ U< ; MSP430FR21xx/23xx/24xx/25xx/26xx
487 \ ==============================================================================
488 \ driver for RTC without calendar
489 \ ==============================================================================
491 CREATE RTCSEC 2 ALLOT
492 CREATE RTCMIN 2 ALLOT
493 CREATE RTCHOUR 2 ALLOT
494 CREATE RTCDOW 2 ALLOT
495 CREATE RTCDAY 2 ALLOT
496 CREATE RTCMON 2 ALLOT
497 CREATE RTCYEAR 2 ALLOT
499 \ ************************************\
500 HDNCODE RTC_INT \ computes sec min hour day month year
501 \ ************************************\
502 ADD #2,RSP \ remove previous_SR
503 BIT #1,&RTCIV \ clear RTC_IFG
504 ADD.B #1,&RTCSEC \ sec+1
507 MOV.B #0,&RTCSEC \ sec=0
508 ADD.B #1,&RTCMIN \ min+1
511 MOV.B #0,&RTCMIN \ min=0
512 ADD.B #1,&RTCHOUR \ hour+1
515 MOV.B #0,&RTCHOUR \ hour=0
516 ADD.B #1,&RTCDOW \ dow+1
519 MOV.B #0,&RTCDOW \ dow=0
521 ADD.B #1,&RTCDAY \ day+1
522 CMP.B #2,&RTCMON \ February month ?
523 \ ------------------------\ here we compute leap year
540 MOV TOS,X \ X = 29|30
542 \ ------------------------\
543 ELSE \ month other than Feb
547 0>= IF \ month >= August?
552 ADD #1,X \ 31 days / month
556 U>= IF \ max day of month is exceeded
557 MOV.B #1,&RTCDAY \ day=1
558 ADD.B #1,&RTCMON \ mon+1
561 MOV.B #1,&RTCMON \ mon=1
562 ADD #1,&RTCYEAR \ year+1
568 MOV @RSP+,PC \ RET to BACKGrouND routine, with GIE disabled
571 \ ------------------------\
572 HDNCODE STOP_RTC \ define STOP_RTC as new COLD_APP subroutine, called by {RTC}|WIPE|RST|COLD|SYS_failures.
573 \ ------------------------\ ------------------------------------------
574 CMP #RET_ADR,&{RTC}+8 \
575 0<> IF \ and only if RTC_APP is started by START_RTC
577 MOV #RET_ADR,-2(X) \ restore {RTC}+8 default value
578 MOV @X+,&RTC_VEC \ restore previous RTC_VEC content from {RTC}+10
579 MOV @X+,&COLD+2 \ restore previous STOP_APP from {RTC}+12 to COLD_PFA
580 MOV @X+,&WARM+2 \ restore previous INI_APP from {RTC}+14 to WARM_PFA
581 \ MOV @X+,&SLEEP+2 \ restore previous BACKGND_APP from {RTC}+16 to SLEEP_PFA
583 \ ------------------------\
584 MOV #0,&RTCCTL \ stops RTC and RTC_INT, see RTC15 in MSP430FR2xxx errata sheet
585 MOV.B #XIN,X \ X = bit_position of XT1 Xtal
586 BIC.B X,&XT1_SEL \ XIN as GPIO
587 BIS.B X,&XT1_DIR \ XIN as output
588 BIC.B X,&XT1_OUT \ RTC15 :"toggle twice XIN ouput"
589 BIS.B X,&XT1_OUT \ "with at least 2 rising or falling edges".
592 BIC.B X,&XT1_DIR \ restore default state of XIN
593 BIS.B X,&XT1_SEL \ XIN as XT1 input
594 \ ------------------------\
595 MOV &COLD+2,PC \ 5 link (branch) to the previous STOP_APP subroutine,
596 \ ------------------------\ then RET to MARKER_DOES or to COLD+4
598 \ ------------------------\
600 \ ----------------------------------------\
601 HDNCODE INI_RTC \ define INI_HDWR_APP called first by START_RTC then by WARM
602 \ ----------------------------------------\ ---------------------------------------------------------
603 CALL &{RTC}+14 \ call previous INI_APP (which sets TOS = RSTIV_MEM)
604 CMP #0,&RTCCTL \ if RTCCTL = 0 = reset state, app is STOPPED and must to be started
605 0= IF \ and if RTCCTL <> 0, we don't restart app and no time is lost.
606 MOV #$7F,&RTCMOD \ RTCMOD = 127
607 BIT #-1,&RTCIV \ clear RTC_IFG
608 MOV #%0010_0110_0100_0010,&RTCCTL \ starts RTC with XT1CLK/256, enables RTC_INT
610 MOV @RSP+,PC \ RET to BODYWARM|START_RTC
612 \ ----------------------------------------\
614 \\ -------------------------------------------------------------------------------
615 \\ WARNING! because RTC_INT have higher priority than eUSCI used for TERMINAL,
616 \\ BACKGND_APP default subroutine execute pending RTC_INT, so you can download a file without RTC time lost.
617 \\ but if you manualy type a command, pending RTC_INT may not be executed during this time.
618 \\ -------------------------------------------------------------------------------
619 \\ --------------------\
620 \\ HDNCODE BACKGND_RTC \ define BACKGND_RTC to replace actual BACKGND_APP
621 \\ --------------------\
623 \ MOV &LPM_MODE,SR \ enter to SLEEP mode, waiting RTC_INT
624 \ AGAIN \ loop back to BEGIN is executed before CPU shut down
625 \\ --------------------\
627 \\ -------------------------------------------------------------------------------
628 \\ WARNING! because unlinked, this BACKGND_APP doesn't execute XON, TERMINAL is MUTEd
629 \\ but maybe that is what you want: RTC time keeps its accuracy.
630 \\ -------------------------------------------------------------------------------
632 \ --------------------------------\
633 CODE START_RTC \ save current content of WARM_PFA, COLD_PFA, SLEEP_PFA, RTC_VEC
634 \ --------------------------------\ then replace them by INI_RTC, STOP_RTC, BACKGND_RTC, RTC_INT then execute INI_RTC.
635 CMP #STOP_RTC,&{RTC}+8 \ content of {RTC}+8 = STOP_RTC ?
637 MOV #STOP_RTC,&{RTC}+8 \ STOP_RTC must be executed by MARKER_DOES of {RTC}, else RTC15 hangs out!
638 MOV &RTC_VEC,&{RTC}+10 \ save content of RTC_VEC to {RTC}+10...
639 MOV #RTC_INT,&RTC_VEC \ then set RTC_VEC with RTC_INT
640 MOV &COLD+2,&{RTC}+12 \ save content of COLD_PFA to {RTC}+12...
641 MOV #STOP_RTC,&COLD+2 \ ...and replace it by STOP_RTC, else RTC15 hangs out with Deep_RST!
642 MOV &WARM+2,&{RTC}+14 \ save content of WARM_PFA to {RTC}+14...
643 MOV #INI_RTC,&WARM+2 \ ...and replace it by INI_RTC
644 \ MOV &SLEEP+2,&{RTC}+16 \ save content of SLEEP_PFA to {RTC}+16...
645 \ MOV #BACKGND_RTC,&SLEEP+2 \ ...and replace it by BACKGND_RTC
649 \ --------------------------------\
651 \ --------------------------------\
653 : TIME? \ display time
654 RTCHOUR C@ 2 U.R $3A EMIT
655 RTCMIN C@ 2 U.R $3A EMIT
659 : TIME! \ hour min sec ---
660 START_RTC \ if not yet done, obviously!
662 U< IF \ if 3 numbers on stack
670 : DATE? \ display date
674 \ ==============================================================================
675 \ driver RTC for RTC_B|RTC_C hardware with calendar
676 \ ==============================================================================
680 BIT.B #RTCRDY,&RTCCTL1
681 0<> UNTIL \ wait until RTCRDY high
683 RTCHOUR C@ 2 U.R $3A EMIT
684 RTCMIN C@ 2 U.R $3A EMIT
690 U< IF \ if 3 numbers on stack
698 CODE DATE? \ display date
700 BIT.B #RTCRDY,&RTCCTL1
701 0<> UNTIL \ wait until windows time RTC_ReaDY is high
706 \ ==============================================================================
707 \ end of RTC software|harware calendar
708 \ ==============================================================================
709 \ resume with common part of DATE? definition:
711 RTCDOW C@ \ -- weekday {0=Sat...6=Fri}
723 RTCDAY C@ \ -- year mon day
725 2 U.R $2F EMIT \ -- year mon
726 2 U.R $2F EMIT \ -- year
732 : DATE! \ year mon day --
734 U< IF \ if 3 numbers on stack
741 RTCYEAR @ \ -- day mon year
742 \ ------------------------------------------
743 \ Zeller's congruence for gregorian calendar
744 \ see https://www.rosettacode.org/wiki/Day_of_the_week#Forth
745 \ : ZELLER \ day mon year -- weekday {0=Sat, ..., 6=Fri}
747 \ IF 1- SWAP 12 + SWAP
748 \ THEN \ -- d m' y' with m' {3=March, ..., 14=february}
749 \ 100 /MOD \ -- d m' K J with K = y' in century, J = century
750 \ DUP 4 / SWAP 2* - \ -- d m' K (J/4 - 2J)
751 \ SWAP DUP 4 / + + \ -- d m' ((J/4 - 2J) + (K + K/4))
752 \ SWAP 1+ 13 5 */ + + \ -- (d + (((J/4 - 2J) + (K + K/4)) + (m+1)*13/5))
753 \ 7 MOD \ -- weekday = {0=Sat, ..., 6=Fri}
754 \ ------------------------------------------
756 IF 1 - SWAP 12 + SWAP
757 THEN \ -- d m' y' with m' {3=March, ..., 14=february}
758 100 U/MOD \ -- d m' K J with K = y' in century, J = century
759 DUP 4 U/ SWAP 2* - \ -- d m' K (J/4 - 2J)
760 SWAP DUP 4 U/ + + \ -- d m' ((J/4 - 2J) + (K + K/4))
761 SWAP 1+ 13 5 U*/ + + \ -- (d + (((J/4 - 2J) + (K + K/4)) + (m+1)*13/5))
762 7 UMOD \ -- weekday = {0=Sat, ..., 6=Fri}
763 \ ------------------------------------------
771 CODE S_ \ Squote alias with blank instead quote separator
772 MOV #0,&CAPS \ turn CAPS OFF
774 XSQUOTE , \ compile run-time code
775 $20 WORD \ -- c-addr (= HERE)
777 MOV.B @TOS,TOS \ -- len compile string
778 ADD #1,TOS \ -- len+1
780 ADDC TOS,&DP \ store aligned DP
782 MOV @RSP+,IP \ pop paired with push COLON
783 MOV #$20,&CAPS \ turn CAPS ON (default state)
791 0= IF MOV @IP+,PC \ interpret time usage disallowed
795 POSTPONE LITERAL \ compile-time code : lit $1B
796 POSTPONE EMIT \ compile-time code : EMIT
797 POSTPONE S_ \ compile-time code : S_ <escape_sequence>
798 POSTPONE TYPE \ compile-time code : TYPE
802 [UNDEFINED] >BODY [IF]
803 \ https://forth-standard.org/standard/core/toBODY
804 \ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word
811 [UNDEFINED] EXECUTE [IF] \ "
812 \ https://forth-standard.org/standard/core/EXECUTE
813 \ EXECUTE i*x xt -- j*x execute Forth word at 'xt'
817 MOV @RSP+,PC \ 4 xt --> PC
821 [UNDEFINED] EVALUATE [IF]
822 \ https://forth-standard.org/standard/core/EVALUATE
823 \ EVALUATE \ i*x c-addr u -- j*x interpret string
825 MOV #SOURCE_LEN,X \ 2
826 MOV @X+,S \ 2 S = SOURCE_LEN
827 MOV @X+,T \ 2 T = SOURCE_ORG
828 MOV @X+,W \ 2 W = TOIN
829 PUSHM #4,IP \ 6 PUSHM IP,S,T,W
834 MOV @RSP+,&SOURCE_ORG \ 4
835 MOV @RSP+,&SOURCE_LEN \ 4
842 ESC [8;40;80t \ set terminal display 42L * 80C
843 39 0 DO CR LOOP \ to avoid erasing any line of source, create 42 empty lines
844 ESC [H \ then set cursor home
847 ['] ACCEPT >BODY \ find default part of deferred ACCEPT (terminal input)
848 EXECUTE \ wait human input for D M Y
849 EVALUATE \ interpret this input
853 ['] ACCEPT >BODY \ find default part of deferred ACCEPT (terminal input)
854 EXECUTE \ wait human input for H M S
855 EVALUATE \ interpret this input
857 RST_STATE \ remove code beyond RST_HERE