X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=MSP430-FORTH%2FPROG100k.f;fp=MSP430-FORTH%2FPROG100k.f;h=0000000000000000000000000000000000000000;hb=a66f5cf4f547d8e0384632b92f652c120f5a70b5;hp=60f2128f938a8554c7ca80c6783dae11db15c5b2;hpb=8561ca8973ea7e51c18be09eddb422b112ef11ff;p=fast-forth%2Fmaster.git diff --git a/MSP430-FORTH/PROG100k.f b/MSP430-FORTH/PROG100k.f deleted file mode 100644 index 60f2128..0000000 --- a/MSP430-FORTH/PROG100k.f +++ /dev/null @@ -1,41675 +0,0 @@ -\ -*- coding: utf-8 -*- - -; ----------------------------------- -; PROG100k.f = 76 x RC5toLCD.f -; ----------------------------------- -; download source file sized to compile 100 kbytes -; ----------------------------------- - -\ TARGET SELECTION ( = the name of \INC\target.pat file without the extension) -\ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989 -\ MSP_EXP430FR2355 -\ LP_MSP430FR2476 -\ -\ from scite editor : copy your target selection in (shift+F8) parameter 1: -\ -\ OR -\ -\ drag and drop this file onto SendSourceFileToTarget.bat -\ then select your TARGET when asked. -\ -\ -\ REGISTERS USAGE -\ R4 to R7 must be saved before use and restored after -\ scratch registers Y to S are free for use -\ under interrupt, IP is free for use -\ interrupts reset SR register ! -\ -\ PUSHM order : PSP,TOS, IP, S, T, W, X, Y, rEXIT,rDOVAR,rDOCON, rDODOES, R3, SR,RSP, PC -\ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0 -\ -\ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack -\ -\ POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP -\ POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15 -\ -\ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack -\ -\ ASSEMBLER conditionnal usage after IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>= -\ ASSEMBLER conditionnal usage before ?JMP ?GOTO : S< S>= U< U>= 0= 0<> 0< -\ -\ FORTH conditionnal : 0= 0< = < > U< -\ -\ display on a LCD 2x20 CHAR the code sent by an IR remote under philips RC5 protocol -\ target : any TI MSP-EXP430FRxxxx launchpad (FRAM) -\ LPM_MODE = LPM0 because use SMCLK for LCDVo -\ -\ DEMO : driver for IR remote compatible with the PHILIPS RC5 protocol -\ plus : driver for 5V LCD 2x20 characters display with 4 bits data interface -\ without usage of an auxiliary 5V to feed the LCD_Vo -\ and without potentiometer to adjust the LCD contrast : -\ to adjust LCD contrast, just press S1 (-) or S2 (+) -\ LCDVo current consumption ~ 500 uA. -\ -\ =================================================================================== -\ notice : adjust WDT_TIM_EX0,LCD_TIM_CTL,LCD_TIM_EX0 and 20_us to the target frequency if <> 8MHz ! -\ =================================================================================== -\ -\ -\ layout : I/O are defined in the launchpad.pat file (don't work with ChipStick_FR2433) -\ -\ GND <-------+---0V0----------> 1 LCD_Vss -\ VCC >------ | --3V6-----+----> 2 LCD_Vdd -\ | | -\ ___ 470n --- -\ ^ --- -\ / \ 1N4148 | -\ --- | -\ 100n | 2k2 | -\ LCD_TIM_.2 >---||--+--^/\/\/v--+----> 3 LCD_Vo (= 0V6 without modulation) -\ -------------------------> 4 LCD_RW -\ -------------------------> 5 LCD_RW -\ -------------------------> 6 LCD_EN -\ <------------------------> 11 LCD_DB4 -\ <------------------------> 12 LCD_DB5 -\ <------------------------> 13 LCD_DB5 -\ <------------------------> 14 LCD_DB7 -\ -\ <----- LCD contrast + <--- Sw1 <--- (finger) :-) -\ <----- LCD contrast - <--- Sw2 <--- (finger) :-) -\ -\ rc5 <--- OUT IR_Receiver (1 TSOP32236) - -\ first, we test for downloading driver only if UART TERMINAL target -CODE ABORT_RC5TOLCD -SUB #2,PSP -MOV TOS,0(PSP) -MOV &VERSION,TOS -SUB #308,TOS \ FastForth V3.8 -COLON -'CR' EMIT \ return to column 1 without 'LF' -ABORT" FastForth V3.8 please!" -PWR_STATE \ remove ABORT_UARTI2CS definition before resuming -; - -ABORT_RC5TOLCD - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - -[DEFINED] {RC5TOLCD} [IF] {RC5TOLCD} [THEN] \ remove application - -MARKER {RC5TOLCD} \ restore the state before MARKER definition -\ \ {UARTI2CS}+8 = RET_ADR: by default MARKER_DOES does CALL #RET_ADR -6 ALLOT \ {UARTI2CS}+10: make room to save previous INI_APP address - \ {RC5TOLCD}+12: make room to save previous WDT_TIM_0_VEC - \ {RC5TOLCD}+14: make room to save previous IR_VEC - -[UNDEFINED] CONSTANT [IF] -\ https://forth-standard.org/standard/core/CONSTANT -\ CONSTANT n -- define a Forth CONSTANT -: CONSTANT -CREATE -HI2LO -MOV TOS,-2(W) \ PFA = n -MOV @PSP+,TOS -MOV @RSP+,IP -MOV @IP+,PC -ENDCODE -[THEN] - -[UNDEFINED] STATE [IF] -\ https://forth-standard.org/standard/core/STATE -\ STATE -- a-addr holds compiler state -STATEADR CONSTANT STATE -[THEN] - -[UNDEFINED] = [IF] -\ https://forth-standard.org/standard/core/Equal -\ = x1 x2 -- flag test x1=x2 -CODE = -SUB @PSP+,TOS \ 2 -0<> IF \ 2 - AND #0,TOS \ 1 - MOV @IP+,PC \ 4 -THEN -XOR #-1,TOS \ 1 flag Z = 1 -MOV @IP+,PC \ 4 -ENDCODE -[THEN] - -[UNDEFINED] IF [IF] \ define IF and THEN -\ https://forth-standard.org/standard/core/IF -\ IF -- IFadr initialize conditional forward branch -CODE IF \ immediate -SUB #2,PSP \ -MOV TOS,0(PSP) \ -MOV &DP,TOS \ -- HERE -ADD #4,&DP \ compile one word, reserve one word -MOV #QFBRAN,0(TOS) \ -- HERE compile QFBRAN -ADD #2,TOS \ -- HERE+2=IFadr -MOV @IP+,PC -ENDCODE IMMEDIATE - -\ https://forth-standard.org/standard/core/THEN -\ THEN IFadr -- resolve forward branch -CODE THEN \ immediate -MOV &DP,0(TOS) \ -- IFadr -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] ELSE [IF] -\ https://forth-standard.org/standard/core/ELSE -\ ELSE IFadr -- ELSEadr resolve forward IF branch, leave ELSEadr on stack -CODE ELSE \ immediate -ADD #4,&DP \ make room to compile two words -MOV &DP,W \ W=HERE+4 -MOV #BRAN,-4(W) -MOV W,0(TOS) \ HERE+4 ==> [IFadr] -SUB #2,W \ HERE+2 -MOV W,TOS \ -- ELSEadr -MOV @IP+,PC -ENDCODE IMMEDIATE -[THEN] - -[UNDEFINED] IS [IF] \ define DEFER! and IS - -\ https://forth-standard.org/standard/core/DEFERStore -\ Set the word xt1 to execute xt2. An ambiguous condition exists if xt1 is not for a word defined by DEFER. -CODE DEFER! \ xt2 xt1 -- -MOV @PSP+,2(TOS) \ -- xt1=CFA_DEFER xt2 --> [CFA_DEFER+2] -MOV @PSP+,TOS \ -- -MOV @IP+,PC -ENDCODE - -\ https://forth-standard.org/standard/core/IS -\ IS xt -- -\ used as is : -\ DEFER DISPLAY create a "do nothing" definition (2 CELLS) -\ inline command : ' U. IS DISPLAY U. becomes the runtime of the word DISPLAY -\ or in a definition : ... ['] U. IS DISPLAY ... -\ KEY, EMIT, CR, ACCEPT and WARM are examples of DEFERred words -\ -\ as IS replaces the PFA value of any word, it's a TO alias for VARIABLE and CONSTANT words... - -: IS -STATE @ -IF POSTPONE ['] POSTPONE DEFER! -ELSE ' DEFER! -THEN -; IMMEDIATE -[THEN] - -[UNDEFINED] >BODY [IF] -\ https://forth-standard.org/standard/core/toBODY -\ >BODY -- addr leave BODY of a CREATEd word\ also leave default ACTION-OF primary DEFERred word -CODE >BODY -ADD #4,TOS -MOV @IP+,PC -ENDCODE -[THEN] - -\ CODE 20uS \ n -- 8MHz version -\ BEGIN \ 4 + 16 ~ loop -\ MOV #39,rDOCON \ 39 -\ BEGIN \ 4 ~ loop -\ NOP -\ SUB #1,rDOCON -\ 0= UNTIL -\ SUB #1,TOS \ 1 -\ 0= UNTIL -\ MOV #XDOCON,rDOCON \ 2 -\ MOV @PSP+,TOS -\ MOV @RSP+,IP \ -\ ENDCODE - -CODE 20_US \ n -- n * 20 us -BEGIN \ here we presume that LCD_TIM_IFG = 1... - BEGIN - BIT #1,&LCD_TIM_CTL \ 3 - 0<> UNTIL \ 2 loop until LCD_TIM_IFG set - BIC #1,&LCD_TIM_CTL \ 3 clear LCD_TIM_IFG - SUB #1,TOS \ 1 -U< UNTIL \ 2 ...so add a dummy loop with U< instead of 0= -MOV @PSP+,TOS \ 2 -MOV @IP+,PC \ 4 -ENDCODE - -CODE TOP_LCD \ LCD Sample -\ \ if write : %xxxx_WWWW -- -\ \ if read : -- %0000_RRRR - BIS.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 0-->1 - BIT.B #LCD_RW,&LCD_CMD_IN \ lcd_rw test -0= IF \ write LCD bits pattern - AND.B #LCD_DB,TOS \ - MOV.B TOS,&LCD_DB_OUT \ send LCD_Data - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV @PSP+,TOS \ - MOV @IP+,PC -THEN \ read LCD bits pattern - SUB #2,PSP - MOV TOS,0(PSP) - BIC.B #LCD_EN,&LCD_CMD_OUT \ lcd_en 1-->0 ==> strobe data - MOV.B &LCD_DB_IN,TOS \ get LCD_Data - AND.B #LCD_DB,TOS \ - MOV @IP+,PC -ENDCODE - -CODE LCD_WRC \ char -- Write Char - BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -BW1 SUB #2,PSP \ - MOV TOS,0(PSP) \ -- %xxxx_LLLL %HHHH_LLLL - RRUM #4,TOS \ -- %xxxx_LLLL %xxxx_HHHH - BIC.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=0 - BIS.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as output -COLON \ high level word starts here - TOP_LCD 2 20_US \ write high nibble first - TOP_LCD 2 20_US -; - -CODE LCD_WRF \ func -- Write Fonction - BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 - GOTO BW1 -ENDCODE - -: LCD_CLEAR $01 LCD_WRF 100 20_us ; \ $01 LCD_WrF 80 20_us ==> bad init ! -: LCD_HOME $02 LCD_WRF 100 20_us ; - -\ [UNDEFINED] OR [IF] -\ -\ \ https://forth-standard.org/standard/core/OR -\ \ C OR x1 x2 -- x3 logical OR -\ CODE OR -\ BIS @PSP+,TOS -\ MOV @IP+,PC -\ ENDCODE -\ -\ [THEN] -\ -\ : LCD_ENTRY_SET $04 OR LCD_WrF ; -\ : LCD_DSP_CTRL $08 OR LCD_WrF ; -\ : LCD_DSP_SHIFT $10 OR LCD_WrF ; -\ : LCD_FN_SET $20 OR LCD_WrF ; -\ : LCD_CGRAM_SET $40 OR LCD_WrF ; -\ : LCD_GOTO $80 OR LCD_WrF ; -\ -\ -\ CODE LCD_RDS \ -- status Read Status -\ BIC.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=0 -\ BW1 BIC.B #LCD_DB,&LCD_DB_DIR \ LCD_Data as intput -\ BIS.B #LCD_RW,&LCD_CMD_OUT \ lcd_rw=1 -\ COLON \ starts a FORTH word -\ TOP_LCD 2 20_us \ -- %0000_HHHH -\ TOP_LCD 2 20_us \ -- %0000_HHHH %0000_LLLL -\ HI2LO \ switch from FORTH to assembler -\ RLAM #4,0(PSP) \ -- %HHHH_0000 %0000_LLLL -\ ADD.B @PSP+,TOS \ -- %HHHH_LLLL -\ MOV @RSP+,IP \ restore IP saved by COLON -\ MOV @IP+,PC \ -\ ENDCODE -\ -\ CODE LCD_RDC \ -- char Read Char -\ BIS.B #LCD_RS,&LCD_CMD_OUT \ lcd_rs=1 -\ GOTO BW1 -\ ENDCODE - - -\ ******************************\ -HDNCODE WDT_INT \ Watchdog interrupt routine, warning : not FORTH executable ! -\ ******************************\ -\ XOR.B #LED1,&LED1_OUT \ to visualise WDT -BIT.B #SW2,&SW2_IN \ test switch S2 -0= IF \ case of switch S2 pressed - CMP #19,&LCD_TIM_CCRn \ maxi Ton = 19/20 & VDD=3V6 ==> LCD_Vo = -1V4 - U< IF - ADD #1,&LCD_TIM_CCRn \ action for switch S2 (P2.5) : 150 mV / increment - THEN -ELSE - BIT.B #SW1,&SW1_IN \ test switch S1 input - 0= IF \ case of Switch S1 pressed - CMP #3,&LCD_TIM_CCRn \ mini Ton = 3/20 & VDD=3V6 ==> LCD_Vo = 0V - U>= IF \ - SUB #1,&LCD_TIM_CCRn \ action for switch S1 (P2.6) : -150 mV / decrement - THEN \ - THEN \ -THEN \ -RETI \ 5 -ENDCODE - -\ ******************************\ -HDNCODE RC5_INT \ wake up on Px.RC5 change interrupt -\ ******************************\ -\ IR_RC5 driver \ IP,S,T,W,X,Y registers are free for use -\ ******************************\ -\ \ in : SR(9)=old Toggle bit memory (ADD on) -\ \ SMclock = 8|16|24 MHz -\ \ use : T,W,X,Y, RC5_TIM_ timer, RC5_TIM_R register -\ \ out : X = 0 C6 C5 C4 C3 C2 C1 C0 -\ \ SR(9)=new Toggle bit memory (ADD on) -\ ******************************\ -\ RC5_FirstStartBitHalfCycle: \ -\ ******************************\ division in RC5_TIM_CTL (SMCLK/1|SMCLK/1|SMCLK/2|SMCLK/4|SMCLK/8) -\ FREQ_KHZ @ 8000 = [IF] \ 8 MHz ? -\ MOV #0,&RC5_TIM_EX0 \ predivide by 1 in RC5_TIM_EX0 register, reset value -\ [THEN] -FREQ_KHZ @ 16000 = [IF] \ 16 MHz ? - MOV #1,&RC5_TIM_EX0 \ predivide by 2 in RC5_TIM_EX0 register -[THEN] -FREQ_KHZ @ 24000 = [IF] \ 24 MHz ? - MOV #2,&RC5_TIM_EX0 \ predivide by 3 in RC5_TIM_EX0 register -[THEN] -MOV #1778,X \ RC5_Period * 1us -MOV #14,W \ count of loop -BEGIN \ -\ ******************************\ -\ RC5_HalfCycle \ <--- loop back ---+ with readjusted RC5_Period -\ ******************************\ | -MOV #%1011100100,&RC5_TIM_CTL \ (re)start timer_A | SMCLK/8 time interval,free running,clear RC5_TIM__IFG and RC5_TIM_R -\ RC5_Compute_3/4_Period: \ | - RRUM #1,X \ X=1/2 cycle | - MOV X,Y \ ^ - RRUM #1,Y \ Y=1/4 - ADD X,Y \ Y=3/4 cycle - BEGIN CMP Y,&RC5_TIM_R \ 3 wait 1/2 + 3/4 cycle = n+1/4 cycles - U>= UNTIL \ 2 -\ ******************************\ -\ RC5_SampleOnFirstQuarter \ at n+1/4 cycles, we sample RC5_input, ST2/C6 bit first -\ ******************************\ - BIT.B #RC5,&IR_IN \ C_flag = IR bit - ADDC T,T \ C_flag <-- T(15):T(0) <-- C_flag - MOV.B &IR_IN,&IR_IES \ preset Px_IES.y state for next IFG - BIC.B #RC5,&IR_IFG \ clear Px_IFG.y after 4/4 cycle pin change - SUB #1,W \ decrement count loop -\ \ count = 13 ==> T = x x x x x x x x |x x x x x x x /C6 -\ \ count = 0 ==> T = x x /C6 Tg A4 A3 A2 A1|A0 C5 C4 C3 C2 C1 C0 1 -0<> WHILE \ ----> out of loop ----+ - ADD X,Y \ | Y = n+3/4 cycles = time out because n+1/2 cycles edge is always present - BEGIN \ | - MOV &RC5_TIM_R,X \ 3 | X grows from n+1/4 up to n+3/4 cycles - CMP Y,X \ 1 | cycle time out of bound ? - U>= IF \ 2 ^ | yes: - BIC #$30,&RC5_TIM_CTL \ | | stop timer - GOTO FW1 \ | | quit on truncated RC5 message - THEN \ | | - BIT.B #RC5,&IR_IFG \ 3 | | n+1/2 cycles edge is always present - 0<> UNTIL \ 2 | | -REPEAT \ ----> loop back --+ | with X = new RC5_period value -\ ******************************\ | -\ RC5_SampleEndOf: \ <---------------------+ -\ ******************************\ -BIC #$30,&RC5_TIM_CTL \ stop timer -\ ******************************\ -\ RC5_ComputeNewRC5word \ -\ ******************************\ -RLAM #1,T \ T = x /C6 Tg A4 A3 A2 A1 A0|C5 C4 C3 C2 C1 C0 1 0 -MOV.B T,X \ X = C5 C4 C3 C2 C1 C0 1 0 -RRUM #2,X \ X = 0 0 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_ComputeC6bit \ -\ ******************************\ -BIT #BIT14,T \ test /C6 bit in T -0= IF BIS #BIT6,X \ set C6 bit in X -THEN \ X = 0 C6 C5 C4 C3 C2 C1 C0 -\ ******************************\ -\ RC5_CommandByteIsDone \ -- BASE RC5_code -\ ******************************\ -\ Only New_RC5_Command ADD_ON \ use SR(10) bit as toggle bit -\ ******************************\ -RRUM #3,T \ new toggle bit = T(13) ==> T(10) -XOR @RSP,T \ (new XOR old) Toggle bits -BIT #UF10,T \ repeated RC5_command ? -0= ?GOTO FW2 \ yes, RETI without UF10 change and without action ! -XOR #UF10,0(RSP) \ 5 toggle bit memory -\ ******************************\ -\ Display IR_RC5 code \ -\ ******************************\ -SUB #8,PSP \ TOS -- x x x x TOS -MOV TOS,6(PSP) \ -- Save_TOS x x x TOS -MOV &BASEADR,4(PSP) \ -- Save_TOS Save_Base x x TOS -MOV #$10,&BASEADR \ set hexadecimal base -MOV X,0(PSP) \ -- Save_TOS Save_Base x RC5_code TOS convert number to ascii low word = RC5 byte -MOV #0,TOS \ -- Save_TOS Save_Base x RC5_code 0 convert number to ascii high word = 0 -LO2HI \ switch from assembler to FORTH - LCD_CLEAR \ set LCD cursor at home - <# # #S #36 HOLD #> \ 32 bits conversion as "$xx" - ['] LCD_WRC IS EMIT \ redirect EMIT to LCD - TYPE \ -- Save_TOS Save_Base x adr cnt display "$xx" on LCD - ['] EMIT >BODY IS EMIT \ -- Save_TOS Save_Base TOS restore EMIT -HI2LO \ -- switch from FORTH to assembler -MOV @PSP+,&BASEADR \ -- Save_TOS TOS restore current BASE -MOV @PSP+,TOS \ -- TOS -FW1 FW2 - MOV @RSP+,SR \ restore SR flags - BIC #%1111_1000,SR \ but force CPU Active Mode - RET \ (instead of RETI) -ENDCODE - - -\ ------------------------------\ -HDNCODE STOP_R2L \ define new STOP_APP -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ -0<> IF \ if previous START executing - BIC.B #RC5,&IR_IE \ clear I/O RC5_Int - BIC.B #RC5,&IR_IFG \ clear I/O RC5_Int flag - MOV #0,&LCD_TIM_CTL \ stop LCD_TIMER - MOV #0,&WDT_TIM_CTL \ stop WDT_TIMER - MOV #0,&WDT_TIM_CCTL0 \ clear CCIFG0 disable CCIE0 - MOV #RET_ADR,&{RC5TOLCD}+8 \ clear MARKER_DOES call - MOV &{RC5TOLCD}+10,&WARM+2 \ restore previous ini_APP - MOV &{RC5TOLCD}+12,&WDT_TIM_0_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+14,&IR_VEC \ restore Vector previous value - MOV &{RC5TOLCD}+10,PC \ run previous INI_APP, then RET -THEN -MOV @RSP+,PC \ RET -ENDCODE - -\ ------------------------------\ -CODE STOP \ -\ ------------------------------\ -BW1 \ <-- INI_R2L for some events -CALL #STOP_R2L -COLON \ restore default action of primary DEFERred word WARM (FORTH version) -ECHO \ -." RC5toLCD is removed," -." type START to restart" -ABORT" " -; -\ ------------------------------\ - -\ ------------------------------\ -HDNCODE INI_R2L \ this routine completes the init of system, i.e. FORTH + this app. -\ ------------------------------\ -\ activate I/O \ -\ ------------------------------\ -BIC #1,&PM5CTL0 \ activate I/O to enable SW2 test -\ ------------------------------\ -\ RESET events handling \ search "SYSRSTIV" in your MSP430FRxxxx datasheet to get listing -\ ------------------------------\ -MOV &RSTIV_MEM,TOS \ SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures -CMP #$0E,TOS \ RSTIV_MEM = SVSHIFG SVSH event ? -0<> IF \ if not - CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ? - U>= ?GOTO BW1 \ execute STOP_R2L then RET to BODY of WARM -THEN \ -BIT.B #SW2,&SW2_IN \ hardware SW2+RST ? -0= ?GOTO BW1 \ hardware SW2+RST execute STOP_U2I then RET to BODY of WARM -\ CMP #4,TOS \ hardware RST -\ 0= ?GOTO BW1 \ hardware RST performs STOP. -\ CMP #2,TOS \ Power_ON event -\ 0= ?GOTO BW1 \ uncomment if you want to loose application in this case... -\ CMP #6,TOS \ -\ 0= ?GOTO BW1 \ COLD event performs STOP... uncomment if it's that you want. -\ CMP #$0A,TOS \ -\ 0= ?GOTO BW1 \ fault event (violation memory protected areas) performs STOP -\ CMP #$16,TOS \ -\ U>= ?GOTO BW1 \ all other fault events + Deep Reset perform STOP -MOV #0,&RSTIV_MEM \ clear RSTIV_MEM after use and before next RST event! -\ ------------------------------\ -\ LCD_TIM_CTL = %0000 0010 1001 0100\$3C0 -\ - - \CNTL Counter lentgh \ 00 = 16 bits -\ -- \TBSSEL TimerB clock select \ 10 = SMCLK -\ -- \ID input divider \ 10 = /4 -\ -- \MC Mode Control \ 01 = up to LCD_TIM_CCR0 -\ - \TBCLR TimerB Clear -\ - \TBIE -\ -\TBIFG -\ -------------------------------\ -\ LCD_TIM_CCTLx = %0000 0000 0110 0000\$3C{2,4,6,8,A,C,E} -\ -- \CM Capture Mode -\ -- \CCIS -\ - \SCS -\ -- \CLLD -\ - \CAP -\ --- \OUTMOD \ 011 = set/reset -\ - \CCIE -\ - \CCI -\ - \OUT -\ - \COV -\ -\CCIFG -\ -------------------------------\ -\ LCD_TIM_CCRx \ -\ -------------------------------\ -\ LCD_TIM_EX0 \ -\ ------------------------------\ -\ set LCD_TIM_ to make 50kHz PWM \ for LCD_Vo; works without interrupt -\ ------------------------------\ -MOV #%10_1101_0100,&LCD_TIM_CTL \ SMCLK/8, up mode, clear timer, no int -\ MOV #0,&LCD_TIM_EX0 \ predivide by 1 in LCD_TIM_EX0 register (8 MHZ) -FREQ_KHZ @ 16000 = [IF] \ if 16 MHz - MOV #1,&LCD_TIM_EX0 \ predivide by 2 in LCD_TIM_EX0 register (16 MHZ) -[THEN] -FREQ_KHZ @ 24000 = [IF] \ if 24 MHz - MOV #2,&LCD_TIM_EX0 \ predivide by 3 in LCD_TIM_EX0 register (24 MHZ) -[THEN] - MOV #19,&LCD_TIM_CCR0 \ 19+1=20*1us=20us -\ ------------------------------\ -\ set LCD_TIM_.2 to generate PWM for LCD_Vo -\ ------------------------------\ -MOV #%0110_0000,&LCD_TIM_CCTLn \ output mode = set/reset \ clear CCIFG - MOV #10,&LCD_TIM_CCRn \ contrast adjust : 10/20 ==> LCD_Vo = -0V6|+3V6 (Vcc=3V6) -\ MOV #12,&LCD_TIM_CCRn \ contrast adjust : 12/20 ==> LCD_Vo = -1V4|+3V3 (Vcc=3V3) -\ ------------------------------\ - BIS.B #LCDVo,&LCDVo_DIR \ - BIS.B #LCDVo,&LCDVo_SEL \ SEL.2 -\ ------------------------------\ - BIS.B #LCD_CMD,&LCD_CMD_DIR \ lcd_cmd as outputs - BIC.B #LCD_CMD,&LCD_CMD_REN \ lcd_cmd pullup/down disable -\ ------------------------------\ - BIS.B #LCD_DB,&LCD_DB_DIR \ as output, wired to DB(4-7) LCD_Data - BIC.B #LCD_DB,&LCD_DB_REN \ LCD_Data pullup/down disable -\ ******************************\ -\ init RC5_Int \ -\ ******************************\ - BIS.B #RC5,&IR_IE \ enable RC5_Int - BIC.B #RC5,&IR_IFG \ reset RC5_Int flag -\ ******************************\ -\ init WatchDog WDT_TIM_ \ eUSCI_A0 (FORTH terminal) has higher priority than WDT_TIM_ -\ ******************************\ -\ %01 0001 0100 \ TAxCTL -\ -- \ TASSEL CLK = ACLK = LFXT = 32768 Hz -\ -- \ ID divided by 1 -\ -- \ MC MODE = up to TAxCCRn -\ - \ TACLR clear timer count -\ - \ TAIE -\ - \ TAIFG -\ ------------------------------\ -MOV #%01_0001_0100,&WDT_TIM_CTL \ start WDT_TIM_, ACLK, up mode, disable int, -\ ------------------------------\ -\ 000 \ TAxEX0 -\ --- \ TAIDEX pre divisor -\ ------------------------------\ -\ %0000 0000 0000 0101 \ TAxCCR0 - MOV ##3276,&WDT_TIM_CCR0 \ else init WDT_TIM_ for LFXT: 32768/20=1638 ==> 100ms -\ ------------------------------\ -\ %0000 0000 0001 0000 \ TAxCCTL0 -\ - \ CAP capture/compare mode = compare -\ - \ CCIEn -\ - \ CCIFGn - MOV #%10000,&WDT_TIM_CCTL0 \ enable compare interrupt, clear CCIFG0 -\ ------------------------------\ -\ define LPM mode for ACCEPT \ -\ ------------------------------\ -\ MOV #LPM4+GIE,&LPM_MODE \ with MSP430FR59xx -\ MOV #LPM2+GIE,&LPM_MODE \ with MSP430FR57xx, terminal input don't work for LPMx > 2 -\ \ with MSP430FR2xxx, terminal input don't work for LPMx > 0 ; LPM0 is the default value -\ ------------------------------\ -COLON \ -\ ------------------------------\ -\ Init LCD 2x20 \ -\ ------------------------------\ - #1000 20_US \ 1- wait 20 ms - %011 TOP_LCD \ 2- send DB5=DB4=1 - #205 20_US \ 3- wait 4,1 ms - %011 TOP_LCD \ 4- send again DB5=DB4=1 - #5 20_US \ 5- wait 0,1 ms - %011 TOP_LCD \ 6- send again again DB5=DB4=1 - #2 20_US \ wait 40 us = LCD cycle - %010 TOP_LCD \ 7- send DB5=1 DB4=0 - #2 20_US \ wait 40 us = LCD cycle - %00101000 LCD_WRF \ 8- %001DNFxx "FonctionSet" D=8/4 DataBus width, Number of lines=2/1, Font bold/normal - %1000 LCD_WRF \ 9- %1DCB "DisplayControl" : Display off, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - %0110 LCD_WRF \ 11- %01xx "LCD_EntrySet" : address and cursor shift after writing in RAM - %1100 LCD_WRF \ 12- %1DCB "DisplayControl" : Display on, Cursor off, Blink off. - LCD_CLEAR \ 10- "LCD_Clear" - ['] LCD_HOME IS CR \ ' CR redirected to LCD_HOME - ['] LCD_WRC IS EMIT \ ' EMIT redirected to LCD_WrC - CR ." I love you" \ display message on LCD - ['] CR >BODY IS CR \ CR executes its default value - ['] EMIT >BODY IS EMIT \ EMIT executes its defaulte value - ." RC5toLCD is running. Type STOP to quit" \ display message on FastForth Terminal - ABORT" " \ -; \ -\ ------------------------------\ - -\ ------------------------------\ -CODE START \ this routine replaces WARM and COLD default values by these of this application. -\ ------------------------------\ -CMP #RET_ADR,&{RC5TOLCD}+8 \ init R2L once, only if MARKER_DOES is not initialized -0= IF \ if not done, customizes MARKER_DOES - MOV #STOP_R2L,&{RC5TOLCD}+8 \ execution of {RC5TOLCD} will perform STOP_R2L. - MOV &WARM+2,&{RC5TOLCD}+10 \ save previous INI_APP subroutine - MOV #INI_R2L,&WARM+2 \ replace it by RC5toLCD INI_APP - MOV &WDT_TIM_0_VEC,&{RC5TOLCD}+12 \ save Vector previous value - MOV #WDT_INT,&WDT_TIM_0_VEC \ for only CCIFG0 int, this interrupt clears automatically CCIFG0 - MOV &IR_VEC,&{RC5TOLCD}+14 \ save Vector previous value - MOV #RC5_INT,&IR_VEC \ init interrupt vector - MOV #INI_R2L,PC \ then execute new INI_APP, without return -THEN -MOV @IP+,PC -ENDCODE -\ ------------------------------\ - - - -ECHO - ; downloading PROG100k.4th is done -RST_HERE ; this app is protected against - -\ START